diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-04 15:21:49 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-10-04 15:21:49 +0000 |
commit | 0ae6bbb1889ae56b291faf50667b006c12005e68 (patch) | |
tree | 26c17cc57f9b457b9ec14cc351810c153d48c88c | |
parent | cca451588a16d338ff8b58456529a40a7c27e7bd (diff) | |
parent | 6b87cde39465cf8b7f42839d8e34d56dc509266d (diff) | |
download | native-0ae6bbb1889ae56b291faf50667b006c12005e68.tar.gz |
Merge "Snap for 10900817 from efed5f1359e547e0afb60c1fa6335d9be9c44320 to sdk-release" into sdk-releaseplatform-tools-34.0.5
231 files changed, 3438 insertions, 1760 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 81056262c3..5719a09a16 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -692,7 +692,7 @@ static bool verifyKernelTraceFuncs(const char* funcs) while (func) { if (!strchr(func, '*')) { String8 fancyFunc = String8::format("\n%s\n", func); - bool found = funcList.find(fancyFunc.string(), 0) >= 0; + bool found = funcList.find(fancyFunc.c_str(), 0) >= 0; if (!found || func[0] == '\0') { fprintf(stderr, "error: \"%s\" is not a valid kernel function " "to trace.\n", func); @@ -796,11 +796,11 @@ static bool setCategoriesEnableFromFile(const char* categories_file) bool ok = true; while (!tokenizer->isEol()) { String8 token = tokenizer->nextToken(" "); - if (token.isEmpty()) { + if (token.empty()) { tokenizer->skipDelimiters(" "); continue; } - ok &= setCategoryEnable(token.string()); + ok &= setCategoryEnable(token.c_str()); } delete tokenizer; return ok; diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index c3cf2c2a60..3e6d2e01f8 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -93,6 +93,10 @@ on late-init chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_set_priority/enable chmod 0666 /sys/kernel/tracing/events/binder/binder_set_priority/enable + chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_command/enable + chmod 0666 /sys/kernel/tracing/events/binder/binder_command/enable + chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_return/enable + chmod 0666 /sys/kernel/tracing/events/binder/binder_return/enable chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable chmod 0666 /sys/kernel/tracing/events/i2c/enable chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable @@ -228,10 +232,6 @@ on late-init chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable -# Tracing disabled by default - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - # Read and truncate the kernel trace. chmod 0666 /sys/kernel/debug/tracing/trace chmod 0666 /sys/kernel/tracing/trace @@ -310,11 +310,9 @@ on late-init chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable -on late-init && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 802922 - setprop persist.traced.enable 0 - write /sys/kernel/debug/tracing/tracing_on 1 - write /sys/kernel/tracing/tracing_on 1 +on late-init && property:ro.boot.fastboot.boottrace= + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -527,7 +525,6 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1 chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id - on property:persist.debug.atrace.boottrace=1 start boottrace @@ -536,10 +533,3 @@ service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categ user root disabled oneshot - -on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 0 - setprop persist.traced.enable 1 - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp index c3d2601444..27ef78854c 100644 --- a/cmds/cmd/Android.bp +++ b/cmds/cmd/Android.bp @@ -27,6 +27,9 @@ cc_library_static { "libselinux", "libbinder", ], + whole_static_libs: [ + "libc++fs", + ], cflags: [ "-Wall", diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 8f1c01ab2c..0ce7711574 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -27,6 +27,7 @@ #include <utils/Mutex.h> #include <utils/Vector.h> +#include <filesystem> #include <getopt.h> #include <stdlib.h> #include <stdio.h> @@ -69,16 +70,14 @@ public: virtual int openFile(const String16& path, const String16& seLinuxContext, const String16& mode) { String8 path8(path); - char cwd[256]; - getcwd(cwd, 256); - String8 fullPath(cwd); - fullPath.appendPath(path8); + auto fullPath = std::filesystem::current_path(); + fullPath /= path8.c_str(); if (!mActive) { mErrorLog << "Open attempt after active for: " << fullPath << endl; return -EPERM; } #if DEBUG - ALOGD("openFile: %s, full=%s", path8.string(), fullPath.string()); + ALOGD("openFile: %s, full=%s", path8.c_str(), fullPath.c_str()); #endif int flags = 0; bool checkRead = false; @@ -96,10 +95,10 @@ public: flags = O_RDWR; checkRead = checkWrite = true; } else { - mErrorLog << "Invalid mode requested: " << mode.string() << endl; + mErrorLog << "Invalid mode requested: " << mode.c_str() << endl; return -EINVAL; } - int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG); + int fd = open(fullPath.c_str(), flags, S_IRWXU|S_IRWXG); #if DEBUG ALOGD("openFile: fd=%d", fd); #endif @@ -109,29 +108,29 @@ public: if (is_selinux_enabled() && seLinuxContext.size() > 0) { String8 seLinuxContext8(seLinuxContext); char* tmp = nullptr; - getfilecon(fullPath.string(), &tmp); + getfilecon(fullPath.c_str(), &tmp); Unique_SecurityContext context(tmp); if (checkWrite) { - int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), + int accessGranted = selinux_check_access(seLinuxContext8.c_str(), context.get(), "file", "write", nullptr); if (accessGranted != 0) { #if DEBUG ALOGD("openFile: failed selinux write check!"); #endif close(fd); - mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl; + mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.c_str() << ", context " << seLinuxContext8.c_str() << ")" << endl; return -EPERM; } } if (checkRead) { - int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(), + int accessGranted = selinux_check_access(seLinuxContext8.c_str(), context.get(), "file", "read", nullptr); if (accessGranted != 0) { #if DEBUG ALOGD("openFile: failed selinux read check!"); #endif close(fd); - mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl; + mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.c_str() << ", context " << seLinuxContext8.c_str() << ")" << endl; return -EPERM; } } diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index aa42541a66..615701ccc1 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -207,6 +207,7 @@ std::string PropertiesHelper::build_type_ = ""; int PropertiesHelper::dry_run_ = -1; int PropertiesHelper::unroot_ = -1; int PropertiesHelper::parallel_run_ = -1; +int PropertiesHelper::strict_run_ = -1; bool PropertiesHelper::IsUserBuild() { if (build_type_.empty()) { @@ -237,6 +238,14 @@ bool PropertiesHelper::IsParallelRun() { return parallel_run_ == 1; } +bool PropertiesHelper::IsStrictRun() { + if (strict_run_ == -1) { + // Defaults to using stricter timeouts. + strict_run_ = android::base::GetBoolProperty("dumpstate.strict_run", true) ? 1 : 0; + } + return strict_run_ == 1; +} + int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); if (fd.get() < 0) { diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index b00c46e0db..9e955e3c04 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -193,11 +193,19 @@ class PropertiesHelper { */ static bool IsParallelRun(); + /* + * Strict-run mode is determined by the `dumpstate.strict_run` sysprop which + * will default to true. This results in shortened timeouts for flaky + * sections. + */ + static bool IsStrictRun(); + private: static std::string build_type_; static int dry_run_; static int unroot_; static int parallel_run_; + static int strict_run_; }; /* diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index dc0e26b9a3..e18c8e380d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -186,6 +186,7 @@ void add_mountinfo(); #define CGROUPFS_DIR "/sys/fs/cgroup" #define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk" #define DROPBOX_DIR "/data/system/dropbox" +#define PRINT_FLAGS "/system/bin/printflags" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -820,9 +821,12 @@ void Dumpstate::PrintHeader() const { RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"}, CommandOptions::WithTimeout(1).Always().Build()); printf("Bugreport format version: %s\n", version_.c_str()); - printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n", - id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(), - options_->args.c_str(), options_->bugreport_mode_string.c_str()); + printf( + "Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d strict_run=%d args=%s " + "bugreport_mode=%s\n", + id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(), + PropertiesHelper::IsStrictRun(), options_->args.c_str(), + options_->bugreport_mode_string.c_str()); printf("\n"); } @@ -1044,7 +1048,8 @@ static void DumpIncidentReport() { MYLOGE("Could not open %s to dump incident report.\n", path.c_str()); return; } - RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build()); + RunCommandToFd(fd, "", {"incident", "-u"}, + CommandOptions::WithTimeout(PropertiesHelper::IsStrictRun() ? 20 : 120).Build()); bool empty = 0 == lseek(fd, 0, SEEK_END); if (!empty) { // Use a different name from "incident.proto" @@ -1414,12 +1419,12 @@ static void DumpHals(int out_fd = STDOUT_FILENO) { auto ret = sm->list([&](const auto& interfaces) { for (const std::string& interface : interfaces) { std::string cleanName = interface; - std::replace_if(cleanName.begin(), - cleanName.end(), - [](char c) { - return !isalnum(c) && - std::string("@-_:.").find(c) == std::string::npos; - }, '_'); + std::replace_if( + cleanName.begin(), cleanName.end(), + [](char c) { + return !isalnum(c) && std::string("@-_.").find(c) == std::string::npos; + }, + '_'); const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName; bool empty = false; @@ -1750,6 +1755,14 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("SYSTEM PROPERTIES", {"getprop"}); + DumpFile("SYSTEM BUILD-TIME RELEASE FLAGS", "/system/etc/build_flags.json"); + DumpFile("SYSTEM_EXT BUILD-TIME RELEASE FLAGS", "/system_ext/etc/build_flags.json"); + DumpFile("PRODUCT BUILD-TIME RELEASE FLAGS", "/product/etc/build_flags.json"); + DumpFile("VENDOR BUILD-TIME RELEASE FLAGS", "/vendor/etc/build_flags.json"); + + RunCommand("ACONFIG FLAGS", {PRINT_FLAGS}, + CommandOptions::WithTimeout(10).Always().DropRoot().Build()); + RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); @@ -3053,6 +3066,12 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n"); } + if (PropertiesHelper::IsStrictRun()) { + MYLOGI( + "Running on strict-run mode, which has shorter timeouts " + "(to disable, call 'setprop dumpstate.strict_run false')\n"); + } + MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n", id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str()); diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index 3d2bdf1d6f..6c4e4b3bc3 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -543,7 +543,7 @@ status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::mi if ((status == TIMED_OUT) && (!asProto)) { std::string msg = StringPrintf("\n*** SERVICE '%s' DUMP TIMEOUT (%llums) EXPIRED ***\n\n", - String8(serviceName).string(), timeout.count()); + String8(serviceName).c_str(), timeout.count()); WriteStringToFd(msg, fd); } @@ -562,6 +562,6 @@ void Dumpsys::writeDumpFooter(int fd, const String16& serviceName, oss << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S"); std::string msg = StringPrintf("--------- %.3fs was the duration of dumpsys %s, ending at: %s\n", - elapsedDuration.count(), String8(serviceName).string(), oss.str().c_str()); + elapsedDuration.count(), String8(serviceName).c_str(), oss.str().c_str()); WriteStringToFd(msg, fd); } diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp index b17cba15d5..fd1df35aee 100644 --- a/cmds/installd/CrateManager.cpp +++ b/cmds/installd/CrateManager.cpp @@ -29,9 +29,10 @@ #include <sys/xattr.h> #include <unistd.h> +#include <utils.h> #include <fstream> +#include <functional> #include <string> -#include <utils.h> #include "utils.h" diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h index 1f30b5dc79..d9b590f784 100644 --- a/cmds/installd/CrateManager.h +++ b/cmds/installd/CrateManager.h @@ -25,6 +25,7 @@ #include <sys/stat.h> #include <sys/types.h> +#include <functional> #include <optional> #include <string> #include <vector> diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index c6132e8ceb..073d0c4854 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -19,6 +19,7 @@ #include <errno.h> #include <fts.h> #include <inttypes.h> +#include <linux/fsverity.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -51,6 +52,7 @@ #include <android-base/unique_fd.h> #include <cutils/ashmem.h> #include <cutils/fs.h> +#include <cutils/misc.h> #include <cutils/properties.h> #include <cutils/sched_policy.h> #include <linux/quota.h> @@ -84,6 +86,8 @@ using android::base::ParseUint; using android::base::Split; using android::base::StringPrintf; +using android::base::unique_fd; +using android::os::ParcelFileDescriptor; using std::endl; namespace android { @@ -229,6 +233,14 @@ binder::Status checkArgumentFileName(const std::string& path) { return ok(); } +binder::Status checkUidInAppRange(int32_t appUid) { + if (FIRST_APPLICATION_UID <= appUid && appUid <= LAST_APPLICATION_UID) { + return ok(); + } + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("UID %d is outside of the range", appUid)); +} + #define ENFORCE_UID(uid) { \ binder::Status status = checkUid((uid)); \ if (!status.isOk()) { \ @@ -236,6 +248,22 @@ binder::Status checkArgumentFileName(const std::string& path) { } \ } +// we could have tighter checks, but this is only to avoid hard errors. Negative values are defined +// in UserHandle.java and carry specific meanings that may not be handled by certain APIs here. +#define ENFORCE_VALID_USER(userId) \ + { \ + if (static_cast<uid_t>(userId) >= std::numeric_limits<uid_t>::max() / AID_USER_OFFSET) { \ + return error("userId invalid: " + std::to_string(userId)); \ + } \ + } + +#define ENFORCE_VALID_USER_OR_NULL(userId) \ + { \ + if (static_cast<uid_t>(userId) != USER_NULL) { \ + ENFORCE_VALID_USER(userId); \ + } \ + } + #define CHECK_ARGUMENT_UUID(uuid) { \ binder::Status status = checkArgumentUuid((uuid)); \ if (!status.isOk()) { \ @@ -273,6 +301,14 @@ binder::Status checkArgumentFileName(const std::string& path) { } \ } +#define CHECK_ARGUMENT_UID_IN_APP_RANGE(uid) \ + { \ + binder::Status status = checkUidInAppRange((uid)); \ + if (!status.isOk()) { \ + return status; \ + } \ + } + #ifdef GRANULAR_LOCKS /** @@ -373,6 +409,33 @@ using PackageLockGuard = std::lock_guard<PackageLock>; } // namespace +binder::Status InstalldNativeService::FsveritySetupAuthToken::authenticate( + const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId) { + int open_flags = fcntl(authFd.get(), F_GETFL); + if (open_flags < 0) { + return exception(binder::Status::EX_SERVICE_SPECIFIC, "fcntl failed"); + } + if ((open_flags & O_ACCMODE) != O_WRONLY && (open_flags & O_ACCMODE) != O_RDWR) { + return exception(binder::Status::EX_SECURITY, "Received FD with unexpected open flag"); + } + if (fstat(authFd.get(), &this->mStatFromAuthFd) < 0) { + return exception(binder::Status::EX_SERVICE_SPECIFIC, "fstat failed"); + } + if (!S_ISREG(this->mStatFromAuthFd.st_mode)) { + return exception(binder::Status::EX_SECURITY, "Not a regular file"); + } + // Don't accept a file owned by a different app. + uid_t uid = multiuser_get_uid(userId, appUid); + if (this->mStatFromAuthFd.st_uid != uid) { + return exception(binder::Status::EX_SERVICE_SPECIFIC, "File not owned by appUid"); + } + return ok(); +} + +bool InstalldNativeService::FsveritySetupAuthToken::isSameStat(const struct stat& st) const { + return memcmp(&st, &mStatFromAuthFd, sizeof(st)) == 0; +} + status_t InstalldNativeService::start() { IPCThreadState::self()->disableBackgroundScheduling(true); status_t ret = BinderService<InstalldNativeService>::publish(); @@ -694,8 +757,9 @@ static binder::Status createAppDataDirs(const std::string& path, int32_t uid, in binder::Status InstalldNativeService::createAppDataLocked( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo, - int32_t targetSdkVersion, int64_t* _aidl_return) { + int32_t targetSdkVersion, int64_t* ceDataInode, int64_t* deDataInode) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -703,7 +767,8 @@ binder::Status InstalldNativeService::createAppDataLocked( const char* pkgname = packageName.c_str(); // Assume invalid inode unless filled in below - if (_aidl_return != nullptr) *_aidl_return = -1; + if (ceDataInode != nullptr) *ceDataInode = -1; + if (deDataInode != nullptr) *deDataInode = -1; int32_t uid = multiuser_get_uid(userId, appId); @@ -741,12 +806,12 @@ binder::Status InstalldNativeService::createAppDataLocked( // And return the CE inode of the top-level data directory so we can // clear contents while CE storage is locked - if (_aidl_return != nullptr) { + if (ceDataInode != nullptr) { ino_t result; if (get_path_inode(path, &result) != 0) { return error("Failed to get_path_inode for " + path); } - *_aidl_return = static_cast<uint64_t>(result); + *ceDataInode = static_cast<uint64_t>(result); } } if (flags & FLAG_STORAGE_DE) { @@ -765,6 +830,14 @@ binder::Status InstalldNativeService::createAppDataLocked( if (!prepare_app_profile_dir(packageName, appId, userId)) { return error("Failed to prepare profiles for " + packageName); } + + if (deDataInode != nullptr) { + ino_t result; + if (get_path_inode(path, &result) != 0) { + return error("Failed to get_path_inode for " + path); + } + *deDataInode = static_cast<uint64_t>(result); + } } if (flags & FLAG_STORAGE_SDK) { @@ -790,6 +863,8 @@ binder::Status InstalldNativeService::createAppDataLocked( binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t appId, int32_t flags) { + ENFORCE_VALID_USER(userId); + int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId); if (sdkSandboxUid == -1) { // There no valid sdk sandbox process for this app. Skip creation of data directory @@ -826,25 +901,30 @@ binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory( binder::Status InstalldNativeService::createAppData( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo, - int32_t targetSdkVersion, int64_t* _aidl_return) { + int32_t targetSdkVersion, int64_t* ceDataInode, int64_t* deDataInode) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); return createAppDataLocked(uuid, packageName, userId, flags, appId, previousAppId, seInfo, - targetSdkVersion, _aidl_return); + targetSdkVersion, ceDataInode, deDataInode); } binder::Status InstalldNativeService::createAppData( const android::os::CreateAppDataArgs& args, android::os::CreateAppDataResult* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(args.userId); // Locking is performed depeer in the callstack. int64_t ceDataInode = -1; + int64_t deDataInode = -1; auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId, - args.previousAppId, args.seInfo, args.targetSdkVersion, &ceDataInode); + args.previousAppId, args.seInfo, args.targetSdkVersion, + &ceDataInode, &deDataInode); _aidl_return->ceDataInode = ceDataInode; + _aidl_return->deDataInode = deDataInode; _aidl_return->exceptionCode = status.exceptionCode(); _aidl_return->exceptionMessage = status.exceptionMessage(); return ok(); @@ -854,6 +934,10 @@ binder::Status InstalldNativeService::createAppDataBatched( const std::vector<android::os::CreateAppDataArgs>& args, std::vector<android::os::CreateAppDataResult>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + for (const auto& arg : args) { + ENFORCE_VALID_USER(arg.userId); + } + // Locking is performed depeer in the callstack. std::vector<android::os::CreateAppDataResult> results; @@ -868,6 +952,7 @@ binder::Status InstalldNativeService::createAppDataBatched( binder::Status InstalldNativeService::reconcileSdkData( const android::os::ReconcileSdkDataArgs& args) { + ENFORCE_VALID_USER(args.userId); // Locking is performed depeer in the callstack. return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId, @@ -891,6 +976,7 @@ binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std:: int userId, int appId, int previousAppId, const std::string& seInfo, int flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -974,6 +1060,7 @@ binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std:: binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1041,6 +1128,7 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag binder::Status InstalldNativeService::clearAppData(const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1132,6 +1220,7 @@ binder::Status InstalldNativeService::clearAppData(const std::optional<std::stri binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags) { + ENFORCE_VALID_USER(userId); const char* uuid_ = uuid ? uuid->c_str() : nullptr; const char* pkgname = packageName.c_str(); @@ -1218,6 +1307,7 @@ binder::Status InstalldNativeService::deleteReferenceProfile(const std::string& binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1288,6 +1378,8 @@ binder::Status InstalldNativeService::destroyAppData(const std::optional<std::st binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags) { + ENFORCE_VALID_USER(userId); + const char* uuid_ = uuid ? uuid->c_str() : nullptr; const char* pkgname = packageName.c_str(); @@ -1435,6 +1527,7 @@ binder::Status InstalldNativeService::snapshotAppData(const std::optional<std::s int32_t userId, int32_t snapshotId, int32_t storageFlags, int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1569,6 +1662,7 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot( const int32_t appId, const std::string& seInfo, const int32_t userId, const int32_t snapshotId, int32_t storageFlags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1641,6 +1735,7 @@ binder::Status InstalldNativeService::destroyAppDataSnapshot( const int32_t userId, const int64_t ceSnapshotInode, const int32_t snapshotId, int32_t storageFlags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1674,6 +1769,7 @@ binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified( const std::optional<std::string>& volumeUuid, const int32_t userId, const std::vector<int32_t>& retainSnapshotIds) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid); LOCK_USER(); @@ -1755,7 +1851,8 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::optional<std::s } if (!createAppDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE, - appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr) + appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr, + nullptr) .isOk()) { res = error("Failed to create package target"); goto fail; @@ -1864,6 +1961,7 @@ fail: binder::Status InstalldNativeService::createUserData(const std::optional<std::string>& uuid, int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); LOCK_USER(); @@ -1884,6 +1982,7 @@ binder::Status InstalldNativeService::createUserData(const std::optional<std::st binder::Status InstalldNativeService::destroyUserData(const std::optional<std::string>& uuid, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); LOCK_USER(); @@ -2671,6 +2770,7 @@ binder::Status InstalldNativeService::getUserSize(const std::optional<std::strin int32_t userId, int32_t flags, const std::vector<int32_t>& appIds, std::vector<int64_t>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); // NOTE: Locking is relaxed on this method, since it's limited to // read-only measurements without mutation. @@ -2806,6 +2906,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional<std::s int32_t userId, int32_t flags, const std::vector<int32_t>& appIds, std::vector<int64_t>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); // NOTE: Locking is relaxed on this method, since it's limited to // read-only measurements without mutation. @@ -2926,6 +3027,7 @@ binder::Status InstalldNativeService::getAppCrates( const std::vector<std::string>& packageNames, int32_t userId, std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); for (const auto& packageName : packageNames) { CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -2975,6 +3077,7 @@ binder::Status InstalldNativeService::getUserCrates( const std::optional<std::string>& uuid, int32_t userId, std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); #ifdef ENABLE_STORAGE_CRATES LOCK_USER(); @@ -3018,6 +3121,7 @@ binder::Status InstalldNativeService::getUserCrates( binder::Status InstalldNativeService::setAppQuota(const std::optional<std::string>& uuid, int32_t userId, int32_t appId, int64_t cacheQuota) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); std::lock_guard<std::recursive_mutex> lock(mQuotasLock); @@ -3261,6 +3365,7 @@ binder::Status InstalldNativeService::restoreconAppData(const std::optional<std: const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -3271,6 +3376,7 @@ binder::Status InstalldNativeService::restoreconAppDataLocked( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -3302,6 +3408,7 @@ binder::Status InstalldNativeService::restoreconSdkDataLocked( const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -3753,6 +3860,7 @@ binder::Status InstalldNativeService::prepareAppProfile(const std::string& packa int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath, const std::optional<std::string>& dexMetadata, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER_OR_NULL(userId); CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(codePath); LOCK_PACKAGE_USER(); @@ -3775,6 +3883,7 @@ binder::Status InstalldNativeService::migrateLegacyObbData() { binder::Status InstalldNativeService::cleanupInvalidPackageDirs( const std::optional<std::string>& uuid, int32_t userId, int32_t flags) { + ENFORCE_VALID_USER(userId); const char* uuid_cstr = uuid ? uuid->c_str() : nullptr; if (flags & FLAG_STORAGE_CE) { @@ -3814,5 +3923,84 @@ binder::Status InstalldNativeService::getOdexVisibility( return *_aidl_return == -1 ? error() : ok(); } +// Creates an auth token to be used in enableFsverity. This token is really to store a proof that +// the caller can write to a file, represented by the authFd. Effectively, system_server as the +// attacker-in-the-middle cannot enable fs-verity on arbitrary app files. If the FD is not writable, +// return null. +// +// appUid and userId are passed for additional ownership check, such that one app can not be +// authenticated for another app's file. These parameters are assumed trusted for this purpose of +// consistency check. +// +// Notably, creating the token allows us to manage the writable FD easily during enableFsverity. +// Since enabling fs-verity to a file requires no outstanding writable FD, passing the authFd to the +// server allows the server to hold the only reference (as long as the client app doesn't). +binder::Status InstalldNativeService::createFsveritySetupAuthToken( + const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId, + sp<IFsveritySetupAuthToken>* _aidl_return) { + CHECK_ARGUMENT_UID_IN_APP_RANGE(appUid); + ENFORCE_VALID_USER(userId); + + auto token = sp<FsveritySetupAuthToken>::make(); + binder::Status status = token->authenticate(authFd, appUid, userId); + if (!status.isOk()) { + return status; + } + *_aidl_return = token; + return ok(); +} + +// Enables fs-verity for filePath, which must be an absolute path and the same inode as in the auth +// token previously returned from createFsveritySetupAuthToken, and owned by the app uid. As +// installd is more privileged than its client / system server, we attempt to limit what a +// (compromised) client can do. +// +// The reason for this app request to go through installd is to avoid exposing a risky area (PKCS#7 +// signature verification) in the kernel to the app as an attack surface (it can't be system server +// because it can't override DAC and manipulate app files). Note that we should be able to drop +// these hops and simply the app calls the ioctl, once all upgrading devices run with a kernel +// without fs-verity built-in signature (https://r.android.com/2650402). +binder::Status InstalldNativeService::enableFsverity(const sp<IFsveritySetupAuthToken>& authToken, + const std::string& filePath, + const std::string& packageName, + int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(filePath); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + LOCK_PACKAGE(); + if (authToken == nullptr) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Received a null auth token"); + } + + // Authenticate to check the targeting file is the same inode as the authFd. + sp<IBinder> authTokenBinder = IInterface::asBinder(authToken)->localBinder(); + if (authTokenBinder == nullptr) { + return exception(binder::Status::EX_SECURITY, "Received a non-local auth token"); + } + auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder); + unique_fd rfd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + struct stat stFromPath; + if (fstat(rfd.get(), &stFromPath) < 0) { + *_aidl_return = errno; + return ok(); + } + if (!authTokenInstance->isSameStat(stFromPath)) { + LOG(DEBUG) << "FD authentication failed"; + *_aidl_return = EPERM; + return ok(); + } + + fsverity_enable_arg arg = {}; + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = 4096; + if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, &arg) < 0) { + *_aidl_return = errno; + } else { + *_aidl_return = 0; + } + return ok(); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 521afc3f97..1ec092d8b5 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -19,6 +19,7 @@ #define COMMANDS_H_ #include <inttypes.h> +#include <sys/stat.h> #include <unistd.h> #include <shared_mutex> @@ -35,8 +36,26 @@ namespace android { namespace installd { +using IFsveritySetupAuthToken = android::os::IInstalld::IFsveritySetupAuthToken; + class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld { public: + class FsveritySetupAuthToken : public os::IInstalld::BnFsveritySetupAuthToken { + public: + FsveritySetupAuthToken() : mStatFromAuthFd() {} + + binder::Status authenticate(const android::os::ParcelFileDescriptor& authFd, int32_t appUid, + int32_t userId); + bool isSameStat(const struct stat& st) const; + + private: + // Not copyable or movable + FsveritySetupAuthToken(const FsveritySetupAuthToken&) = delete; + FsveritySetupAuthToken& operator=(const FsveritySetupAuthToken&) = delete; + + struct stat mStatFromAuthFd; + }; + static status_t start(); static char const* getServiceName() { return "installd"; } virtual status_t dump(int fd, const Vector<String16> &args) override; @@ -49,7 +68,8 @@ public: binder::Status createAppData(const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo, - int32_t targetSdkVersion, int64_t* _aidl_return); + int32_t targetSdkVersion, int64_t* ceDataInode, + int64_t* deDataInode); binder::Status createAppData( const android::os::CreateAppDataArgs& args, @@ -192,6 +212,13 @@ public: const std::optional<std::string>& outputPath, int32_t* _aidl_return); + binder::Status createFsveritySetupAuthToken(const android::os::ParcelFileDescriptor& authFd, + int32_t appUid, int32_t userId, + android::sp<IFsveritySetupAuthToken>* _aidl_return); + binder::Status enableFsverity(const android::sp<IFsveritySetupAuthToken>& authToken, + const std::string& filePath, const std::string& packageName, + int32_t* _aidl_return); + private: std::recursive_mutex mLock; std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock; @@ -212,7 +239,7 @@ private: const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion, - int64_t* _aidl_return); + int64_t* ceDataInode, int64_t* deDataInode); binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo); diff --git a/cmds/installd/binder/android/os/CreateAppDataResult.aidl b/cmds/installd/binder/android/os/CreateAppDataResult.aidl index 3b8fa6b9f2..463489e01e 100644 --- a/cmds/installd/binder/android/os/CreateAppDataResult.aidl +++ b/cmds/installd/binder/android/os/CreateAppDataResult.aidl @@ -19,6 +19,7 @@ package android.os; /** {@hide} */ parcelable CreateAppDataResult { long ceDataInode; + long deDataInode; int exceptionCode; @utf8InCpp String exceptionMessage; } diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 9ad853b1df..8893e38c03 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -134,6 +134,22 @@ interface IInstalld { int getOdexVisibility(@utf8InCpp String packageName, @utf8InCpp String apkPath, @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath); + interface IFsveritySetupAuthToken { + // Using an interface here is an easy way to create and maintain an IBinder object across + // the processes. When installd creates this binder object, it stores the file stat + // privately for later authentication, and only returns the reference to the caller process. + // Once the binder object has no reference count, it gets destructed automatically + // (alternatively, installd can maintain an internal mapping, but it is more error prone + // because the app may crash and not finish the fs-verity setup, keeping the memory unused + // forever). + // + // We don't necessarily need a method here, so it's left blank intentionally. + } + IFsveritySetupAuthToken createFsveritySetupAuthToken(in ParcelFileDescriptor authFd, int appUid, + int userId); + int enableFsverity(in IFsveritySetupAuthToken authToken, @utf8InCpp String filePath, + @utf8InCpp String packageName); + const int FLAG_STORAGE_DE = 0x1; const int FLAG_STORAGE_CE = 0x2; const int FLAG_STORAGE_EXTERNAL = 0x4; diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index 5cf402c54c..df02588a22 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -18,6 +18,7 @@ #define DEXOPT_H_ #include "installd_constants.h" +#include "unique_file.h" #include <sys/types.h> @@ -156,6 +157,10 @@ const char* select_execution_binary( // artifacts. int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir); +UniqueFile maybe_open_reference_profile(const std::string& pkgname, const std::string& dex_path, + const char* profile_name, bool profile_guided, + bool is_public, int uid, bool is_secondary_dex); + } // namespace installd } // namespace android diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 7cabdb09e1..822ab7fbb7 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -14,20 +14,21 @@ ** limitations under the License. */ -#include <algorithm> #include <inttypes.h> -#include <limits> -#include <random> -#include <regex> #include <selinux/android.h> #include <selinux/avc.h> #include <stdlib.h> #include <string.h> #include <sys/capability.h> +#include <sys/mman.h> #include <sys/prctl.h> #include <sys/stat.h> -#include <sys/mman.h> #include <sys/wait.h> +#include <algorithm> +#include <iterator> +#include <limits> +#include <random> +#include <regex> #include <android-base/logging.h> #include <android-base/macros.h> @@ -47,6 +48,7 @@ #include "otapreopt_parameters.h" #include "otapreopt_utils.h" #include "system_properties.h" +#include "unique_file.h" #include "utils.h" #ifndef LOG_TAG @@ -87,6 +89,9 @@ static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE u static_assert(DEXOPT_MASK == (0x3dfe | DEXOPT_IDLE_BACKGROUND_JOB), "DEXOPT_MASK unexpected."); +constexpr const char* kAotCompilerFilters[]{ + "space-profile", "space", "speed-profile", "speed", "everything-profile", "everything", +}; template<typename T> static constexpr bool IsPowerOfTwo(T x) { @@ -415,6 +420,36 @@ private: return (strcmp(arg, "!") == 0) ? nullptr : arg; } + bool IsAotCompilation() const { + if (std::find(std::begin(kAotCompilerFilters), std::end(kAotCompilerFilters), + std::string_view(parameters_.compiler_filter)) == + std::end(kAotCompilerFilters)) { + return false; + } + + int dexopt_flags = parameters_.dexopt_flags; + bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0; + bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0; + bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0; + + if (profile_guided) { + UniqueFile reference_profile = + maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path, + parameters_.profile_name, profile_guided, + is_public, parameters_.uid, is_secondary_dex); + // `maybe_open_reference_profile` installs a hook that clears the profile on + // destruction. Disable it. + reference_profile.DisableCleanup(); + struct stat sbuf; + if (reference_profile.fd() == -1 || + (fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) { + return false; + } + } + + return true; + } + bool ShouldSkipPreopt() const { // There's one thing we have to be careful about: we may/will be asked to compile an app // living in the system image. This may be a valid request - if the app wasn't compiled, @@ -439,9 +474,12 @@ private: // (This is ugly as it's the only thing where we need to understand the contents // of parameters_, but it beats postponing the decision or using the call- // backs to do weird things.) + + // In addition, no need to preopt for "verify". The existing vdex files in the OTA package + // and the /data partition will still be usable after the OTA update is applied. const char* apk_path = parameters_.apk_path; CHECK(apk_path != nullptr); - if (StartsWith(apk_path, android_root_)) { + if (StartsWith(apk_path, android_root_) || !IsAotCompilation()) { const char* last_slash = strrchr(apk_path, '/'); if (last_slash != nullptr) { std::string path(apk_path, last_slash - apk_path + 1); @@ -471,13 +509,18 @@ private: // TODO(calin): embed the profile name in the parameters. int Dexopt() { std::string error; + + int dexopt_flags = parameters_.dexopt_flags; + // Make sure dex2oat is run with background priority. + dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB; + int res = dexopt(parameters_.apk_path, parameters_.uid, parameters_.pkgName, parameters_.instruction_set, parameters_.dexopt_needed, parameters_.oat_dir, - parameters_.dexopt_flags, + dexopt_flags, parameters_.compiler_filter, parameters_.volume_uuid, parameters_.shared_libraries, @@ -521,61 +564,6 @@ private: return Dexopt(); } - //////////////////////////////////// - // Helpers, mostly taken from ART // - //////////////////////////////////// - - // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc. - static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) { - constexpr size_t kPageSize = PAGE_SIZE; - static_assert(IsPowerOfTwo(kPageSize), "page size must be power of two"); - CHECK_EQ(min_delta % kPageSize, 0u); - CHECK_EQ(max_delta % kPageSize, 0u); - CHECK_LT(min_delta, max_delta); - - std::default_random_engine generator; - generator.seed(GetSeed()); - std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta); - int32_t r = distribution(generator); - if (r % 2 == 0) { - r = RoundUp(r, kPageSize); - } else { - r = RoundDown(r, kPageSize); - } - CHECK_LE(min_delta, r); - CHECK_GE(max_delta, r); - CHECK_EQ(r % kPageSize, 0u); - return r; - } - - static uint64_t GetSeed() { -#ifdef __BIONIC__ - // Bionic exposes arc4random, use it. - uint64_t random_data; - arc4random_buf(&random_data, sizeof(random_data)); - return random_data; -#else -#error "This is only supposed to run with bionic. Otherwise, implement..." -#endif - } - - void AddCompilerOptionFromSystemProperty(const char* system_property, - const char* prefix, - bool runtime, - std::vector<std::string>& out) const { - const std::string* value = system_properties_.GetProperty(system_property); - if (value != nullptr) { - if (runtime) { - out.push_back("--runtime-arg"); - } - if (prefix != nullptr) { - out.push_back(StringPrintf("%s%s", prefix, value->c_str())); - } else { - out.push_back(*value); - } - } - } - static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH"; static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT"; static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA"; diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index c86993cb06..c40caf56d8 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -19,9 +19,12 @@ #include <sys/mount.h> #include <sys/stat.h> #include <sys/wait.h> +#include <unistd.h> +#include <algorithm> #include <array> #include <fstream> +#include <iostream> #include <sstream> #include <android-base/file.h> @@ -29,6 +32,7 @@ #include <android-base/macros.h> #include <android-base/scopeguard.h> #include <android-base/stringprintf.h> +#include <android-base/strings.h> #include <android-base/unique_fd.h> #include <libdm/dm.h> #include <selinux/android.h> @@ -37,7 +41,7 @@ #include "otapreopt_utils.h" #ifndef LOG_TAG -#define LOG_TAG "otapreopt" +#define LOG_TAG "otapreopt_chroot" #endif using android::base::StringPrintf; @@ -49,20 +53,22 @@ namespace installd { // so just try the possibilities one by one. static constexpr std::array kTryMountFsTypes = {"ext4", "erofs"}; -static void CloseDescriptor(int fd) { - if (fd >= 0) { - int result = close(fd); - UNUSED(result); // Ignore result. Printing to logcat will open a new descriptor - // that we do *not* want. - } -} - static void CloseDescriptor(const char* descriptor_string) { int fd = -1; std::istringstream stream(descriptor_string); stream >> fd; if (!stream.fail()) { - CloseDescriptor(fd); + if (fd >= 0) { + if (close(fd) < 0) { + PLOG(ERROR) << "Failed to close " << fd; + } + } + } +} + +static void SetCloseOnExec(int fd) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + PLOG(ERROR) << "Failed to set FD_CLOEXEC on " << fd; } } @@ -129,24 +135,39 @@ static void TryExtraMount(const char* name, const char* slot, const char* target } // Entry for otapreopt_chroot. Expected parameters are: -// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params] -// The file descriptor denoted by status-fd will be closed. The rest of the parameters will -// be passed on to otapreopt in the chroot. +// +// [cmd] [status-fd] [target-slot-suffix] +// +// The file descriptor denoted by status-fd will be closed. Dexopt commands on +// the form +// +// "dexopt" [dexopt-params] +// +// are then read from stdin until EOF and passed on to /system/bin/otapreopt one +// by one. After each call a line with the current command count is written to +// stdout and flushed. static int otapreopt_chroot(const int argc, char **arg) { // Validate arguments - // We need the command, status channel and target slot, at a minimum. - if(argc < 3) { - PLOG(ERROR) << "Not enough arguments."; + if (argc == 2 && std::string_view(arg[1]) == "--version") { + // Accept a single --version flag, to allow the script to tell this binary + // from the earlier one. + std::cout << "2" << std::endl; + return 0; + } + if (argc != 3) { + LOG(ERROR) << "Wrong number of arguments: " << argc; exit(208); } - // Close all file descriptors. They are coming from the caller, we do not want to pass them - // on across our fork/exec into a different domain. - // 1) Default descriptors. - CloseDescriptor(STDIN_FILENO); - CloseDescriptor(STDOUT_FILENO); - CloseDescriptor(STDERR_FILENO); - // 2) The status channel. - CloseDescriptor(arg[1]); + const char* status_fd = arg[1]; + const char* slot_suffix = arg[2]; + + // Set O_CLOEXEC on standard fds. They are coming from the caller, we do not + // want to pass them on across our fork/exec into a different domain. + SetCloseOnExec(STDIN_FILENO); + SetCloseOnExec(STDOUT_FILENO); + SetCloseOnExec(STDERR_FILENO); + // Close the status channel. + CloseDescriptor(status_fd); // We need to run the otapreopt tool from the postinstall partition. As such, set up a // mount namespace and change root. @@ -185,20 +206,20 @@ static int otapreopt_chroot(const int argc, char **arg) { // 2) We're in a mount namespace here, so when we die, this will be cleaned up. // 3) Ignore errors. Printing anything at this stage will open a file descriptor // for logging. - if (!ValidateTargetSlotSuffix(arg[2])) { - LOG(ERROR) << "Target slot suffix not legal: " << arg[2]; + if (!ValidateTargetSlotSuffix(slot_suffix)) { + LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix; exit(207); } - TryExtraMount("vendor", arg[2], "/postinstall/vendor"); + TryExtraMount("vendor", slot_suffix, "/postinstall/vendor"); // Try to mount the product partition. update_engine doesn't do this for us, but we // want it for product APKs. Same notes as vendor above. - TryExtraMount("product", arg[2], "/postinstall/product"); + TryExtraMount("product", slot_suffix, "/postinstall/product"); // Try to mount the system_ext partition. update_engine doesn't do this for // us, but we want it for system_ext APKs. Same notes as vendor and product // above. - TryExtraMount("system_ext", arg[2], "/postinstall/system_ext"); + TryExtraMount("system_ext", slot_suffix, "/postinstall/system_ext"); constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig"; // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot @@ -329,30 +350,37 @@ static int otapreopt_chroot(const int argc, char **arg) { exit(218); } - // Now go on and run otapreopt. + // Now go on and read dexopt lines from stdin and pass them on to otapreopt. - // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc - // Outgoing: cmd + target-slot + cmd... | Outgoing | = argc - 1 - std::vector<std::string> cmd; - cmd.reserve(argc); - cmd.push_back("/system/bin/otapreopt"); + int count = 1; + for (std::array<char, 1000> linebuf; + std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) { + // Subtract one from gcount() since getline() counts the newline. + std::string line(&linebuf[0], std::cin.gcount() - 1); - // The first parameter is the status file descriptor, skip. - for (size_t i = 2; i < static_cast<size_t>(argc); ++i) { - cmd.push_back(arg[i]); - } + if (std::cin.fail()) { + LOG(ERROR) << "Command exceeds max length " << linebuf.size() << " - skipped: " << line; + continue; + } - // Fork and execute otapreopt in its own process. - std::string error_msg; - bool exec_result = Exec(cmd, &error_msg); - if (!exec_result) { - LOG(ERROR) << "Running otapreopt failed: " << error_msg; - } + std::vector<std::string> tokenized_line = android::base::Tokenize(line, " "); + std::vector<std::string> cmd{"/system/bin/otapreopt", slot_suffix}; + std::move(tokenized_line.begin(), tokenized_line.end(), std::back_inserter(cmd)); - if (!exec_result) { - exit(213); + LOG(INFO) << "Command " << count << ": " << android::base::Join(cmd, " "); + + // Fork and execute otapreopt in its own process. + std::string error_msg; + bool exec_result = Exec(cmd, &error_msg); + if (!exec_result) { + LOG(ERROR) << "Running otapreopt failed: " << error_msg; + } + + // Print the count to stdout and flush to indicate progress. + std::cout << count << std::endl; } + LOG(INFO) << "No more dexopt commands"; return 0; } diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh index db5c34edc2..28bd7932a2 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -16,7 +16,9 @@ # limitations under the License. # -# This script will run as a postinstall step to drive otapreopt. +# This script runs as a postinstall step to drive otapreopt. It comes with the +# OTA package, but runs /system/bin/otapreopt_chroot in the (old) active system +# image. See system/extras/postinst/postinst.sh for some docs. TARGET_SLOT="$1" STATUS_FD="$2" @@ -31,12 +33,11 @@ BOOT_PROPERTY_NAME="dev.bootcomplete" BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME) if [ "$BOOT_COMPLETE" != "1" ] ; then - echo "Error: boot-complete not detected." + echo "$0: Error: boot-complete not detected." # We must return 0 to not block sideload. exit 0 fi - # Compute target slot suffix. # TODO: Once bootctl is not restricted, we should query from there. Or get this from # update_engine as a parameter. @@ -45,45 +46,63 @@ if [ "$TARGET_SLOT" = "0" ] ; then elif [ "$TARGET_SLOT" = "1" ] ; then TARGET_SLOT_SUFFIX="_b" else - echo "Unknown target slot $TARGET_SLOT" + echo "$0: Unknown target slot $TARGET_SLOT" exit 1 fi +if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then + # We require an updated chroot wrapper that reads dexopt commands from stdin. + # Even if we kept compat with the old binary, the OTA preopt wouldn't work due + # to missing sepolicy rules, so there's no use spending time trying to dexopt + # (b/291974157). + echo "$0: Current system image is too old to work with OTA preopt - skipping." + exit 0 +fi PREPARE=$(cmd otadexopt prepare) # Note: Ignore preparation failures. Step and done will fail and exit this. # This is necessary to support suspends - the OTA service will keep # the state around for us. -PROGRESS=$(cmd otadexopt progress) -print -u${STATUS_FD} "global_progress $PROGRESS" - -i=0 -while ((i<MAXIMUM_PACKAGES)) ; do +# Create an array with all dexopt commands in advance, to know how many there are. +otadexopt_cmds=() +while (( ${#otadexopt_cmds[@]} < MAXIMUM_PACKAGES )) ; do DONE=$(cmd otadexopt done) if [ "$DONE" = "OTA complete." ] ; then break fi + otadexopt_cmds+=("$(cmd otadexopt next)") +done - DEXOPT_PARAMS=$(cmd otadexopt next) +DONE=$(cmd otadexopt done) +cmd otadexopt cleanup - /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&- +echo "$0: Using streaming otapreopt_chroot on ${#otadexopt_cmds[@]} packages" - PROGRESS=$(cmd otadexopt progress) - print -u${STATUS_FD} "global_progress $PROGRESS" +function print_otadexopt_cmds { + for cmd in "${otadexopt_cmds[@]}" ; do + print "$cmd" + done +} - sleep 1 - i=$((i+1)) -done +function report_progress { + while read count ; do + # mksh can't do floating point arithmetic, so emulate a fixed point calculation. + (( permilles = 1000 * count / ${#otadexopt_cmds[@]} )) + printf 'global_progress %d.%03d\n' $((permilles / 1000)) $((permilles % 1000)) >&${STATUS_FD} + done +} + +print_otadexopt_cmds | \ + /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX | \ + report_progress -DONE=$(cmd otadexopt done) if [ "$DONE" = "OTA incomplete." ] ; then - echo "Incomplete." + echo "$0: Incomplete." else - echo "Complete or error." + echo "$0: Complete or error." fi print -u${STATUS_FD} "global_progress 1.0" -cmd otadexopt cleanup exit 0 diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp index 4221a3a593..7648265f0f 100644 --- a/cmds/installd/run_dex2oat.cpp +++ b/cmds/installd/run_dex2oat.cpp @@ -208,36 +208,13 @@ void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex, } // Compute compiler filter. - { - std::string dex2oat_compiler_filter_arg; - { - // If we are booting without the real /data, don't spend time compiling. - std::string vold_decrypt = GetProperty("vold.decrypt", ""); - bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" || - vold_decrypt == "1"; - - bool have_dex2oat_relocation_skip_flag = false; - if (skip_compilation) { - dex2oat_compiler_filter_arg = "--compiler-filter=extract"; - have_dex2oat_relocation_skip_flag = true; - } else if (compiler_filter != nullptr) { - dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", - compiler_filter); - } - if (have_dex2oat_relocation_skip_flag) { - AddRuntimeArg("-Xnorelocate"); - } - } - - if (dex2oat_compiler_filter_arg.empty()) { - dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter", - "--compiler-filter=%s"); - } - AddArg(dex2oat_compiler_filter_arg); - - if (compilation_reason != nullptr) { - AddArg(std::string("--compilation-reason=") + compilation_reason); - } + if (compiler_filter != nullptr) { + AddArg(StringPrintf("--compiler-filter=%s", compiler_filter)); + } else { + AddArg(MapPropertyToArg("dalvik.vm.dex2oat-filter", "--compiler-filter=%s")); + } + if (compilation_reason != nullptr) { + AddArg(std::string("--compilation-reason=") + compilation_reason); } AddArg(MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size", diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp index 304ba7b04f..56f84a5e12 100644 --- a/cmds/installd/run_dex2oat_test.cpp +++ b/cmds/installd/run_dex2oat_test.cpp @@ -441,24 +441,6 @@ TEST_F(RunDex2OatTest, Runtime) { VerifyExpectedFlags(); } -TEST_F(RunDex2OatTest, SkipRelocationInMinFramework) { - setSystemProperty("vold.decrypt", "trigger_restart_min_framework"); - CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs()); - - SetExpectedFlagUsed("--compiler-filter", "=extract"); - SetExpectedFlagUsed("-Xnorelocate", ""); - VerifyExpectedFlags(); -} - -TEST_F(RunDex2OatTest, SkipRelocationIfDecryptedWithFullDiskEncryption) { - setSystemProperty("vold.decrypt", "1"); - CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs()); - - SetExpectedFlagUsed("--compiler-filter", "=extract"); - SetExpectedFlagUsed("-Xnorelocate", ""); - VerifyExpectedFlags(); -} - TEST_F(RunDex2OatTest, DalvikVmDex2oatFilter) { setSystemProperty("dalvik.vm.dex2oat-filter", "speed"); auto args = RunDex2OatArgs::MakeDefaultTestArgs(); diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index c4071c6020..ee91d80a3b 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -197,6 +197,7 @@ protected: std::string app_oat_dir_; int64_t ce_data_inode_; + int64_t de_data_inode_; std::string secondary_dex_ce_; std::string secondary_dex_ce_link_; @@ -261,16 +262,10 @@ protected: } // Create the app user data. - binder::Status status = service_->createAppData( - volume_uuid_, - package_name_, - kTestUserId, - kAppDataFlags, - kTestAppUid, - 0 /* previousAppId */, - se_info_, - kOSdkVersion, - &ce_data_inode_); + binder::Status status = + service_->createAppData(volume_uuid_, package_name_, kTestUserId, kAppDataFlags, + kTestAppUid, 0 /* previousAppId */, se_info_, kOSdkVersion, + &ce_data_inode_, &de_data_inode_); if (!status.isOk()) { return ::testing::AssertionFailure() << "Could not create app data: " << status.toString8().c_str(); @@ -1350,16 +1345,10 @@ TEST_F(ProfileTest, ProfileDirOkAfterFixup) { ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700)); // Run createAppData again which will offer to fix-up the profile directories. - ASSERT_BINDER_SUCCESS(service_->createAppData( - volume_uuid_, - package_name_, - kTestUserId, - kAppDataFlags, - kTestAppUid, - 0 /* previousAppId */, - se_info_, - kOSdkVersion, - &ce_data_inode_)); + ASSERT_BINDER_SUCCESS(service_->createAppData(volume_uuid_, package_name_, kTestUserId, + kAppDataFlags, kTestAppUid, 0 /* previousAppId */, + se_info_, kOSdkVersion, &ce_data_inode_, + &de_data_inode_)); // Check the file access. CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR); @@ -1492,18 +1481,13 @@ class BootProfileTest : public ProfileTest { void createAppProfilesForBootMerge(size_t number_of_profiles) { for (size_t i = 0; i < number_of_profiles; i++) { int64_t ce_data_inode; + int64_t de_data_inode; std::string package_name = "dummy_test_pkg" + std::to_string(i); LOG(INFO) << package_name; - ASSERT_BINDER_SUCCESS(service_->createAppData( - volume_uuid_, - package_name, - kTestUserId, - kAppDataFlags, - kTestAppUid, - 0 /* previousAppId */, - se_info_, - kOSdkVersion, - &ce_data_inode)); + ASSERT_BINDER_SUCCESS( + service_->createAppData(volume_uuid_, package_name, kTestUserId, kAppDataFlags, + kTestAppUid, 0 /* previousAppId */, se_info_, + kOSdkVersion, &ce_data_inode, &de_data_inode)); extra_apps_.push_back(package_name); extra_ce_data_inodes_.push_back(ce_data_inode); std::string profile = create_current_profile_path( diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index 858a92cc65..4bc92afa18 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -42,9 +42,12 @@ #include "binder_test_utils.h" #include "dexopt.h" #include "globals.h" +#include "unique_file.h" #include "utils.h" using android::base::StringPrintf; +using android::base::unique_fd; +using android::os::ParcelFileDescriptor; using std::filesystem::is_empty; namespace android { @@ -136,6 +139,16 @@ static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode return fd; } +static void create_with_content(const std::string& path, uid_t owner, gid_t group, mode_t mode, + const std::string& content) { + int fd = ::open(path.c_str(), O_RDWR | O_CREAT, mode); + EXPECT_NE(fd, -1); + EXPECT_TRUE(android::base::WriteStringToFd(content, fd)); + EXPECT_EQ(::fchown(fd, owner, group), 0); + EXPECT_EQ(::fchmod(fd, mode), 0); + close(fd); +} + static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) { EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0); } @@ -527,6 +540,94 @@ TEST_F(ServiceTest, GetAppSizeWrongSizes) { externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize)); } + +class FsverityTest : public ServiceTest { +protected: + binder::Status createFsveritySetupAuthToken(const std::string& path, int open_mode, + sp<IFsveritySetupAuthToken>* _aidl_return) { + unique_fd ufd(open(path.c_str(), open_mode)); + EXPECT_GE(ufd.get(), 0) << "open failed: " << strerror(errno); + ParcelFileDescriptor rfd(std::move(ufd)); + return service->createFsveritySetupAuthToken(std::move(rfd), kTestAppId, kTestUserId, + _aidl_return); + } +}; + +TEST_F(FsverityTest, enableFsverity) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect to fs-verity setup to succeed + sp<IFsveritySetupAuthToken> authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken); + EXPECT_TRUE(status.isOk()); + EXPECT_TRUE(authToken != nullptr); + + // Verity auth token works to enable fs-verity + int32_t errno_local; + status = service->enableFsverity(authToken, path, "fake.package.name", &errno_local); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(errno_local, 0); +} + +TEST_F(FsverityTest, enableFsverity_nullAuthToken) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Verity null auth token fails + sp<IFsveritySetupAuthToken> authToken; + int32_t errno_local; + binder::Status status = + service->enableFsverity(authToken, path, "fake.package.name", &errno_local); + EXPECT_FALSE(status.isOk()); +} + +TEST_F(FsverityTest, enableFsverity_differentFile) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect to fs-verity setup to succeed + sp<IFsveritySetupAuthToken> authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken); + EXPECT_TRUE(status.isOk()); + EXPECT_TRUE(authToken != nullptr); + + // Verity auth token does not work for a different file + const std::string anotherPath = kTestPath + "/bar"; + ASSERT_TRUE(android::base::WriteStringToFile("content", anotherPath)); + UniqueFile raii2(/*fd=*/-1, anotherPath, [](const std::string& path) { unlink(path.c_str()); }); + int32_t errno_local; + status = service->enableFsverity(authToken, anotherPath, "fake.package.name", &errno_local); + EXPECT_TRUE(status.isOk()); + EXPECT_NE(errno_local, 0); +} + +TEST_F(FsverityTest, createFsveritySetupAuthToken_ReadonlyFdDoesNotAuthenticate) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect the fs-verity setup to fail + sp<IFsveritySetupAuthToken> authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDONLY, &authToken); + EXPECT_FALSE(status.isOk()); +} + +TEST_F(FsverityTest, createFsveritySetupAuthToken_UnownedFile) { + const std::string path = kTestPath + "/foo"; + // Simulate world-writable file owned by another app + create_with_content(path, kTestAppUid + 1, kTestAppUid + 1, 0666, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect the fs-verity setup to fail + sp<IFsveritySetupAuthToken> authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken); + EXPECT_FALSE(status.isOk()); +} + static bool mkdirs(const std::string& path, mode_t mode) { struct stat sb; if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index ecea1d2b1c..c43fdbd547 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -18,6 +18,7 @@ #ifndef UTILS_H_ #define UTILS_H_ +#include <functional> #include <string> #include <vector> diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index fb69513d24..d73a30bf9b 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -93,22 +93,9 @@ cc_fuzz { libfuzzer_options: [ "max_len=50000", ], - }, -} - -// Adding this new fuzzer to test the corpus generated by record_binder -cc_fuzz { - name: "servicemanager_test_fuzzer", - defaults: [ - "servicemanager_defaults", - "service_fuzzer_defaults", - ], - host_supported: true, - srcs: ["fuzzers/ServiceManagerTestFuzzer.cpp"], - fuzz_config: { - libfuzzer_options: [ - "max_len=50000", + cc: [ + "smoreland@google.com", + "waghpawan@google.com", ], }, - corpus: ["fuzzers/servicemamanager_fuzzer_corpus/*"], } diff --git a/cmds/servicemanager/OWNERS b/cmds/servicemanager/OWNERS new file mode 100644 index 0000000000..7f5a8115d1 --- /dev/null +++ b/cmds/servicemanager/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 32456 + +smoreland@google.com diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index cae9684cc4..facb8b133b 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -18,6 +18,7 @@ #include <android-base/logging.h> #include <android-base/properties.h> +#include <android-base/strings.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> @@ -112,10 +113,26 @@ static bool isVintfDeclared(const std::string& name) { }); if (!found) { + std::set<std::string> instances; + forEachManifest([&](const ManifestWithDescription& mwd) { + std::set<std::string> res = mwd.manifest->getAidlInstances(aname.package, aname.iface); + instances.insert(res.begin(), res.end()); + return true; + }); + + std::string available; + if (instances.empty()) { + available = "No alternative instances declared in VINTF"; + } else { + // for logging only. We can't return this information to the client + // because they may not have permissions to find or list those + // instances + available = "VINTF declared instances: " + base::Join(instances, ", "); + } // Although it is tested, explicitly rebuilding qualified name, in case it // becomes something unexpected. - ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(), - aname.iface.c_str(), aname.instance.c_str()); + ALOGI("Could not find %s.%s/%s in the VINTF manifest. %s.", aname.package.c_str(), + aname.iface.c_str(), aname.instance.c_str(), available.c_str()); } return found; diff --git a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp b/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp deleted file mode 100644 index e19b6eb279..0000000000 --- a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2023 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 <fuzzbinder/libbinder_driver.h> -#include <utils/StrongPointer.h> - -#include "Access.h" -#include "ServiceManager.h" - -using ::android::Access; -using ::android::Parcel; -using ::android::ServiceManager; -using ::android::sp; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - FuzzedDataProvider provider(data, size); - auto accessPtr = std::make_unique<Access>(); - auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr)); - - // Reserved bytes - provider.ConsumeBytes<uint8_t>(8); - uint32_t code = provider.ConsumeIntegral<uint32_t>(); - uint32_t flag = provider.ConsumeIntegral<uint32_t>(); - std::vector<uint8_t> parcelData = provider.ConsumeRemainingBytes<uint8_t>(); - - Parcel inputParcel; - inputParcel.setData(parcelData.data(), parcelData.size()); - - Parcel reply; - serviceManager->transact(code, inputParcel, &reply, flag); - - serviceManager->clear(); - - return 0; -} diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 Binary files differdeleted file mode 100644 index 07319f864e..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 Binary files differdeleted file mode 100644 index 07319f864e..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 Binary files differdeleted file mode 100644 index 07319f864e..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 Binary files differdeleted file mode 100644 index 07319f864e..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 Binary files differdeleted file mode 100644 index e69ab49d5d..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 Binary files differdeleted file mode 100644 index 88ad474f09..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 Binary files differdeleted file mode 100644 index fae15a2fea..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 Binary files differdeleted file mode 100644 index b326907a58..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 Binary files differdeleted file mode 100644 index 05b27bf413..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 Binary files differdeleted file mode 100644 index b326907a58..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 Binary files differdeleted file mode 100644 index cdaa1f01b1..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 Binary files differdeleted file mode 100644 index ff0941b7a6..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 Binary files differdeleted file mode 100644 index cdaa1f01b1..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 Binary files differdeleted file mode 100644 index 7e5f948682..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 Binary files differdeleted file mode 100644 index 07319f864e..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 Binary files differdeleted file mode 100644 index 07319f864e..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 +++ /dev/null diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 Binary files differdeleted file mode 100644 index 39e5104927..0000000000 --- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 +++ /dev/null diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 86a45e61ea..ae56cb0ed3 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -125,6 +125,8 @@ int main(int argc, char** argv) { ps->setThreadPoolMaxThreadCount(0); ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); + IPCThreadState::self()->disableBackgroundScheduling(true); + sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>()); if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { LOG(ERROR) << "Could not self register servicemanager"; diff --git a/data/etc/Android.bp b/data/etc/Android.bp index a737bd3fb7..ca2cc2ac8c 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -77,6 +77,12 @@ prebuilt_etc { } prebuilt_etc { + name: "android.hardware.context_hub.prebuilt.xml", + src: "android.hardware.context_hub.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { name: "android.hardware.ethernet.prebuilt.xml", src: "android.hardware.ethernet.xml", defaults: ["frameworks_native_data_etc_defaults"], @@ -101,6 +107,18 @@ prebuilt_etc { } prebuilt_etc { + name: "android.hardware.nfc.prebuilt.xml", + src: "android.hardware.nfc.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { + name: "android.hardware.nfc.hce.prebuilt.xml", + src: "android.hardware.nfc.hce.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { name: "android.hardware.reboot_escrow.prebuilt.xml", src: "android.hardware.reboot_escrow.xml", defaults: ["frameworks_native_data_etc_defaults"], @@ -173,6 +191,12 @@ prebuilt_etc { } prebuilt_etc { + name: "android.hardware.thread_network.prebuilt.xml", + src: "android.hardware.thread_network.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { name: "android.hardware.usb.accessory.prebuilt.xml", src: "android.hardware.usb.accessory.xml", defaults: ["frameworks_native_data_etc_defaults"], diff --git a/data/etc/android.hardware.thread_network.xml b/data/etc/android.hardware.thread_network.xml new file mode 100644 index 0000000000..b116ed6bf8 --- /dev/null +++ b/data/etc/android.hardware.thread_network.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 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. +--> +<!-- Adds the feature indicating support for the Thread networking protocol --> +<permissions> + <feature name="android.hardware.thread_network" /> +</permissions> diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h index ce30b417e0..165a868d57 100644 --- a/headers/media_plugin/media/openmax/OMX_AsString.h +++ b/headers/media_plugin/media/openmax/OMX_AsString.h @@ -561,6 +561,7 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexConfigPriority: return "ConfigPriority"; case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; + case OMX_IndexParamConsumerUsageBits64: return "ParamConsumerUsageBits64"; case OMX_IndexConfigLatency: return "ConfigLatency"; default: return asString((OMX_INDEXTYPE)i, def); } diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 0af40dd28e..5ddd719ba1 100644 --- a/headers/media_plugin/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h @@ -105,6 +105,7 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */ + OMX_IndexParamConsumerUsageBits64, /**< reference: OMX_PARAM_U64TYPE */ OMX_IndexExtOtherEndUnused, /* Time configurations */ diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 35f87f96ae..87a14c021d 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -196,7 +196,7 @@ enum AndroidBitmapCompressFormat { * * @param userContext Pointer to user-defined data passed to * {@link AndroidBitmap_compress}. - * @param data Compressed data of |size| bytes to write. + * @param data Compressed data of `size` bytes to write. * @param size Length in bytes of data to write. * @return Whether the operation succeeded. */ @@ -205,7 +205,7 @@ typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext, size_t size) __INTRODUCED_IN(30); /** - * Compress |pixels| as described by |info|. + * Compress `pixels` as described by `info`. * * Available since API level 30. * diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index e0a8045d41..645fa8a5e7 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -53,7 +53,7 @@ extern "C" { /** * Create a shared memory region. * - * Create shared memory region and returns an file descriptor. The resulting file descriptor can be + * Create shared memory region and returns a file descriptor. The resulting file descriptor can be * mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory * region can be restricted with {@link ASharedMemory_setProt}. * @@ -65,7 +65,7 @@ extern "C" { * cmsg(3) man pages for more information. * * If you intend to share this file descriptor with a child process after - * calling exec(3), note that you will need to use fcntl(2) with FD_SETFD + * calling exec(3), note that you will need to use fcntl(2) with F_SETFD * to clear the FD_CLOEXEC flag for this to work on all versions of Android. * * Available since API level 26. diff --git a/include/android/thermal.h b/include/android/thermal.h index 32580badc0..1f477f8233 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -188,13 +188,13 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager, * Note that this only attempts to track the headroom of slow-moving sensors, such as * the skin temperature sensor. This means that there is no benefit to calling this function * more frequently than about once per second, and attempted to call significantly - * more frequently may result in the function returning {@code NaN}. + * more frequently may result in the function returning `NaN`. * * In addition, in order to be able to provide an accurate forecast, the system does * not attempt to forecast until it has multiple temperature samples from which to * extrapolate. This should only take a few seconds from the time of the first call, * but during this time, no forecasting will occur, and the current headroom will be - * returned regardless of the value of {@code forecastSeconds}. + * returned regardless of the value of `forecastSeconds`. * * The value returned is a non-negative float that represents how much of the thermal envelope * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is diff --git a/include/ftl/OWNERS b/include/ftl/OWNERS new file mode 100644 index 0000000000..3f6129226a --- /dev/null +++ b/include/ftl/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/native:/services/surfaceflinger/OWNERS
\ No newline at end of file diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index deff76b3a5..f634c1dcde 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -190,6 +190,9 @@ cc_defaults { "-performance-move-const-arg", // b/273486801 "portability*", ], + lto: { + thin: true, + }, } cc_library_headers { diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 8d9955dd6b..589df9aceb 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -261,7 +261,7 @@ std::optional<int32_t> BpBinder::getDebugBinderHandle() const { bool BpBinder::isDescriptorCached() const { Mutex::Autolock _l(mLock); - return mDescriptorCache.string() != kDescriptorUninit.string(); + return mDescriptorCache.c_str() != kDescriptorUninit.c_str(); } const String16& BpBinder::getInterfaceDescriptor() const @@ -279,7 +279,7 @@ const String16& BpBinder::getInterfaceDescriptor() const Mutex::Autolock _l(mLock); // mDescriptorCache could have been assigned while the lock was // released. - if (mDescriptorCache.string() == kDescriptorUninit.string()) mDescriptorCache = res; + if (mDescriptorCache.c_str() == kDescriptorUninit.c_str()) mDescriptorCache = res; } } diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 08169f5538..5ec4e8b25a 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -52,8 +52,8 @@ public: } } else { // An exception was thrown back; fall through to return failure - ALOGD("openContentUri(%s) caught exception %d\n", - String8(stringUri).string(), exceptionCode); + ALOGD("openContentUri(%s) caught exception %d\n", String8(stringUri).c_str(), + exceptionCode); } } return fd; diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 2408307459..6034f2b4ca 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -216,8 +216,8 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP if (res) { if (startTime != 0) { ALOGI("Check passed after %d seconds for %s from uid=%d pid=%d", - (int)((uptimeMillis()-startTime)/1000), - String8(permission).string(), uid, pid); + (int)((uptimeMillis() - startTime) / 1000), String8(permission).c_str(), + uid, pid); } return res; } @@ -225,7 +225,7 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP // Is this a permission failure, or did the controller go away? if (IInterface::asBinder(pc)->isBinderAlive()) { if (logPermissionFailure) { - ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(), + ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).c_str(), uid, pid); } return false; @@ -246,7 +246,7 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP if (startTime == 0) { startTime = uptimeMillis(); ALOGI("Waiting to check permission %s from uid=%d pid=%d", - String8(permission).string(), uid, pid); + String8(permission).c_str(), uid, pid); } sleep(1); } else { @@ -295,7 +295,7 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const // retry interval in millisecond; note that vendor services stay at 100ms const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100; - ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(), + ALOGI("Waiting for service '%s' on '%s'...", String8(name).c_str(), ProcessState::self()->getDriverName().c_str()); int n = 0; @@ -306,12 +306,12 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const sp<IBinder> svc = checkService(name); if (svc != nullptr) { ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms", - String8(name).string(), ProcessState::self()->getDriverName().c_str(), + String8(name).c_str(), ProcessState::self()->getDriverName().c_str(), uptimeMillis() - startTime); return svc; } } - ALOGW("Service %s didn't start. Returning NULL", String8(name).string()); + ALOGW("Service %s didn't start. Returning NULL", String8(name).c_str()); return nullptr; } diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index 03553f36e9..5b1cb7ea56 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -428,7 +428,7 @@ void SimpleBestFitAllocator::dump_l(const char* what) const { String8 result; dump_l(result, what); - ALOGD("%s", result.string()); + ALOGD("%s", result.c_str()); } void SimpleBestFitAllocator::dump(String8& result, diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 9b685f9145..5b34efc257 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -854,7 +854,7 @@ constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T'); // Write RPC headers. (previously just the interface token) status_t Parcel::writeInterfaceToken(const String16& interface) { - return writeInterfaceToken(interface.string(), interface.size()); + return writeInterfaceToken(interface.c_str(), interface.size()); } status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) { @@ -918,7 +918,7 @@ bool Parcel::checkInterface(IBinder* binder) const bool Parcel::enforceInterface(const String16& interface, IPCThreadState* threadState) const { - return enforceInterface(interface.string(), interface.size(), threadState); + return enforceInterface(interface.c_str(), interface.size(), threadState); } bool Parcel::enforceInterface(const char16_t* interface, @@ -977,8 +977,8 @@ bool Parcel::enforceInterface(const char16_t* interface, return true; } else { ALOGW("**** enforceInterface() expected '%s' but read '%s'", - String8(interface, len).string(), - String8(parcel_interface, parcel_interface_len).string()); + String8(interface, len).c_str(), + String8(parcel_interface, parcel_interface_len).c_str()); return false; } } @@ -1376,7 +1376,7 @@ status_t Parcel::writeCString(const char* str) status_t Parcel::writeString8(const String8& str) { - return writeString8(str.string(), str.size()); + return writeString8(str.c_str(), str.size()); } status_t Parcel::writeString8(const char* str, size_t len) @@ -1399,7 +1399,7 @@ status_t Parcel::writeString8(const char* str, size_t len) status_t Parcel::writeString16(const String16& str) { - return writeString16(str.string(), str.size()); + return writeString16(str.c_str(), str.size()); } status_t Parcel::writeString16(const char16_t* str, size_t len) diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp index 670fd55da3..658686d2db 100644 --- a/libs/binder/PermissionCache.cpp +++ b/libs/binder/PermissionCache.cpp @@ -101,9 +101,8 @@ bool PermissionCache::checkPermission( nsecs_t t = -systemTime(); granted = android::checkPermission(permission, pid, uid); t += systemTime(); - ALOGD("checking %s for uid=%d => %s (%d us)", - String8(permission).string(), uid, - granted?"granted":"denied", (int)ns2us(t)); + ALOGD("checking %s for uid=%d => %s (%d us)", String8(permission).c_str(), uid, + granted ? "granted" : "denied", (int)ns2us(t)); pc.cache(permission, uid, granted); } return granted; diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 02b0447304..8ec4af9945 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -401,9 +401,9 @@ void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); - ALOGV("Spawning new pooled thread, name=%s\n", name.string()); + ALOGV("Spawning new pooled thread, name=%s\n", name.c_str()); sp<Thread> t = sp<PoolThread>::make(isMain); - t->run(name.string()); + t->run(name.c_str()); pthread_mutex_lock(&mThreadCountLock); mKernelStartedThreads++; pthread_mutex_unlock(&mThreadCountLock); @@ -505,7 +505,7 @@ status_t ProcessState::enableOnewaySpamDetection(bool enable) { } void ProcessState::giveThreadPoolName() { - androidSetThreadName( makeBinderThreadName().string() ); + androidSetThreadName(makeBinderThreadName().c_str()); } String8 ProcessState::getDriverName() { diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp index 44a9e3befa..324670633f 100644 --- a/libs/binder/RecordedTransaction.cpp +++ b/libs/binder/RecordedTransaction.cpp @@ -124,7 +124,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails( static_cast<int32_t>(timestamp.tv_nsec), 0}; - t.mData.mInterfaceName = std::string(String8(interfaceName).string()); + t.mData.mInterfaceName = std::string(String8(interfaceName).c_str()); if (interfaceName.size() != t.mData.mInterfaceName.size()) { LOG(ERROR) << "Interface Name is not valid. Contains characters that aren't single byte " "utf-8."; diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h index eb98042c42..50158c3072 100644 --- a/libs/binder/include/binder/TextOutput.h +++ b/libs/binder/include/binder/TextOutput.h @@ -147,7 +147,7 @@ inline TextOutput& operator<<(TextOutput& to, const bool &val) inline TextOutput& operator<<(TextOutput& to, const String16& val) { - to << String8(val).string(); + to << String8(val).c_str(); return to; } diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format index 9a9d936f15..60774143ee 100644 --- a/libs/binder/ndk/.clang-format +++ b/libs/binder/ndk/.clang-format @@ -2,9 +2,7 @@ BasedOnStyle: Google ColumnLimit: 100 IndentWidth: 4 ContinuationIndentWidth: 8 -PointerAlignment: Left TabWidth: 4 AllowShortFunctionsOnASingleLine: Inline PointerAlignment: Left -TabWidth: 4 UseTab: Never diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h index d6937c2c52..ed53891e3d 100644 --- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h @@ -115,17 +115,29 @@ class SpAIBinder { */ AIBinder** getR() { return &mBinder; } - bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); } - bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); } - bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); } - bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); } - bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); } - bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); } - private: AIBinder* mBinder = nullptr; }; +#define SP_AIBINDER_COMPARE(_op_) \ + static inline bool operator _op_(const SpAIBinder& lhs, const SpAIBinder& rhs) { \ + return lhs.get() _op_ rhs.get(); \ + } \ + static inline bool operator _op_(const SpAIBinder& lhs, const AIBinder* rhs) { \ + return lhs.get() _op_ rhs; \ + } \ + static inline bool operator _op_(const AIBinder* lhs, const SpAIBinder& rhs) { \ + return lhs _op_ rhs.get(); \ + } + +SP_AIBINDER_COMPARE(!=) +SP_AIBINDER_COMPARE(<) +SP_AIBINDER_COMPARE(<=) +SP_AIBINDER_COMPARE(==) +SP_AIBINDER_COMPARE(>) +SP_AIBINDER_COMPARE(>=) +#undef SP_AIBINDER_COMPARE + namespace impl { /** diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 76c7aacb7c..4786c89c89 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -25,6 +25,7 @@ #pragma once +#include <assert.h> #include <errno.h> #include <stdbool.h> #include <stdint.h> diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp index 8ee396e256..8fb755cdac 100644 --- a/libs/binder/ndk/tests/Android.bp +++ b/libs/binder/ndk/tests/Android.bp @@ -80,6 +80,28 @@ cc_test { require_root: true, } +cc_test_host { + name: "libbinder_ndk_unit_test_host", + defaults: ["test_libbinder_ndk_defaults"], + srcs: ["libbinder_ndk_unit_test_host.cpp"], + test_suites: [ + "general-tests", + ], + test_options: { + unit_test: true, + }, + static_libs: [ + "libbase", + "libbinder_ndk", + "libbinder", + "libcutils", + "libfakeservicemanager", + "libgmock", + "liblog", + "libutils", + ], +} + cc_test { name: "binderVendorDoubleLoadTest", vendor: true, diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 27ce615565..15708ca738 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -39,7 +39,6 @@ #include <condition_variable> #include <iostream> #include <mutex> -#include <optional> #include <thread> #include "android/binder_ibinder.h" @@ -377,18 +376,24 @@ TEST(NdkBinder, CantHaveTwoLocalBinderClassesWithSameDescriptor) { } TEST(NdkBinder, GetTestServiceStressTest) { - // libbinder has some complicated logic to make sure only one instance of - // ABpBinder is associated with each binder. - constexpr size_t kNumThreads = 10; constexpr size_t kNumCalls = 1000; std::vector<std::thread> threads; + // this is not a lazy service, but we must make sure that it's started before calling + // checkService on it, since the other process serving it might not be started yet. + { + // getService, not waitForService, to take advantage of timeout + auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName)); + ASSERT_NE(nullptr, binder.get()); + } + for (size_t i = 0; i < kNumThreads; i++) { threads.push_back(std::thread([&]() { for (size_t j = 0; j < kNumCalls; j++) { auto binder = ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName)); + ASSERT_NE(nullptr, binder.get()); EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); } })); @@ -427,21 +432,6 @@ TEST(NdkBinder, GetLazyService) { EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); } -TEST(NdkBinder, IsUpdatable) { - bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default"); - EXPECT_EQ(isUpdatable, false); -} - -TEST(NdkBinder, GetUpdatableViaApex) { - std::optional<std::string> updatableViaApex; - AServiceManager_getUpdatableApexName( - "android.hardware.light.ILights/default", &updatableViaApex, - [](const char* apexName, void* context) { - *static_cast<std::optional<std::string>*>(context) = apexName; - }); - EXPECT_EQ(updatableViaApex, std::nullopt) << *updatableViaApex; -} - // This is too slow TEST(NdkBinder, CheckLazyServiceShutDown) { ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService)); @@ -755,9 +745,9 @@ TEST(NdkBinder, ConvertToPlatformBinder) { // local ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) { // convert to platform binder - EXPECT_NE(binder.get(), nullptr); + EXPECT_NE(binder, nullptr); sp<IBinder> platformBinder = AIBinder_toPlatformBinder(binder.get()); - EXPECT_NE(platformBinder.get(), nullptr); + EXPECT_NE(platformBinder, nullptr); auto proxy = interface_cast<IBinderNdkUnitTest>(platformBinder); EXPECT_NE(proxy, nullptr); @@ -768,7 +758,7 @@ TEST(NdkBinder, ConvertToPlatformBinder) { // convert back ndk::SpAIBinder backBinder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(platformBinder)); - EXPECT_EQ(backBinder.get(), binder.get()); + EXPECT_EQ(backBinder, binder); } } diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp new file mode 100644 index 0000000000..0a3021d0b0 --- /dev/null +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test_host.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/binder_manager.h> +#include <binder/IServiceManager.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <utils/String16.h> +#include <utils/String8.h> +#include <utils/StrongPointer.h> + +#include <optional> + +#include "fakeservicemanager/FakeServiceManager.h" + +using android::FakeServiceManager; +using android::setDefaultServiceManager; +using android::sp; +using android::String16; +using android::String8; +using testing::_; +using testing::Eq; +using testing::Mock; +using testing::NiceMock; +using testing::Optional; +using testing::Return; + +struct MockServiceManager : FakeServiceManager { + MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&)); +}; + +struct AServiceManager : testing::Test { + static sp<MockServiceManager> mockSM; + + static void InitMock() { + mockSM = new NiceMock<MockServiceManager>; + setDefaultServiceManager(mockSM); + } + + void TearDown() override { Mock::VerifyAndClear(mockSM.get()); } + + void ExpectUpdatableViaApexReturns(std::optional<String16> apexName) { + EXPECT_CALL(*mockSM, updatableViaApex(_)).WillRepeatedly(Return(apexName)); + } +}; + +sp<MockServiceManager> AServiceManager::mockSM; + +TEST_F(AServiceManager, isUpdatableViaApex) { + auto apexFoo = String16("com.android.hardware.foo"); + ExpectUpdatableViaApexReturns(apexFoo); + + bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.foo.IFoo/default"); + EXPECT_EQ(isUpdatable, true); +} + +TEST_F(AServiceManager, isUpdatableViaApex_Not) { + ExpectUpdatableViaApexReturns(std::nullopt); + + bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.foo.IFoo/default"); + EXPECT_EQ(isUpdatable, false); +} + +void getUpdatableApexNameCallback(const char* apexName, void* context) { + *(static_cast<std::optional<std::string>*>(context)) = apexName; +} + +TEST_F(AServiceManager, getUpdatableApexName) { + auto apexFoo = String16("com.android.hardware.foo"); + ExpectUpdatableViaApexReturns(apexFoo); + + std::optional<std::string> result; + AServiceManager_getUpdatableApexName("android.hardware.foo.IFoo/default", &result, + getUpdatableApexNameCallback); + EXPECT_THAT(result, Optional(std::string(String8(apexFoo)))); +} + +TEST_F(AServiceManager, getUpdatableApexName_Null) { + ExpectUpdatableViaApexReturns(std::nullopt); + + std::optional<std::string> result; + AServiceManager_getUpdatableApexName("android.hardware.foo.IFoo/default", &result, + getUpdatableApexNameCallback); + EXPECT_THAT(result, Eq(std::nullopt)); +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + AServiceManager::InitMock(); + return RUN_ALL_TESTS(); +} diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index d36ebac109..57a38dc480 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -11,9 +11,6 @@ rust_library { name: "libbinder_rs", crate_name: "binder", srcs: ["src/lib.rs"], - shared_libs: [ - "libutils", - ], rustlibs: [ "libbinder_ndk_sys", "libdowncast_rs", @@ -97,34 +94,12 @@ rust_bindgen { crate_name: "binder_ndk_bindgen", wrapper_src: "sys/BinderBindings.hpp", source_stem: "bindings", - bindgen_flags: [ + bindgen_flag_files: [ // Unfortunately the only way to specify the rust_non_exhaustive enum // style for a type is to make it the default - "--default-enum-style", - "rust_non_exhaustive", // and then specify constified enums for the enums we don't want // rustified - "--constified-enum", - "android::c_interface::consts::.*", - - "--allowlist-type", - "android::c_interface::.*", - "--allowlist-type", - "AStatus", - "--allowlist-type", - "AIBinder_Class", - "--allowlist-type", - "AIBinder", - "--allowlist-type", - "AIBinder_Weak", - "--allowlist-type", - "AIBinder_DeathRecipient", - "--allowlist-type", - "AParcel", - "--allowlist-type", - "binder_status_t", - "--allowlist-function", - ".*", + "libbinder_ndk_bindgen_flags.txt", ], shared_libs: [ "libbinder_ndk", diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs index 2d2bf7c582..1dc0b2471d 100644 --- a/libs/binder/rust/binder_tokio/lib.rs +++ b/libs/binder/rust/binder_tokio/lib.rs @@ -103,7 +103,12 @@ impl BinderAsyncPool for Tokio { // // This shouldn't cause issues with blocking the thread as only one task will run in a // call to `block_on`, so there aren't other tasks to block. - let result = spawn_me(); + // + // If the `block_in_place` call fails, then you are driving a current-thread runtime on + // the binder threadpool. Instead, it is recommended to use `TokioRuntime<Handle>` when + // the runtime is a current-thread runtime, as the current-thread runtime can be driven + // only by `Runtime::block_on` calls and not by `Handle::block_on`. + let result = tokio::task::block_in_place(spawn_me); Box::pin(after_spawn(result)) } else { let handle = tokio::task::spawn_blocking(spawn_me); diff --git a/libs/binder/rust/libbinder_ndk_bindgen_flags.txt b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt new file mode 100644 index 0000000000..551c59f671 --- /dev/null +++ b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt @@ -0,0 +1,11 @@ +--default-enum-style=rust_non_exhaustive +--constified-enum=android::c_interface::consts::.* +--allowlist-type=android::c_interface::.* +--allowlist-type=AStatus +--allowlist-type=AIBinder_Class +--allowlist-type=AIBinder +--allowlist-type=AIBinder_Weak +--allowlist-type=AIBinder_DeathRecipient +--allowlist-type=AParcel +--allowlist-type=binder_status_t +--allowlist-function=.* diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs index 81f68f5a29..6fda878d07 100644 --- a/libs/binder/rust/rpcbinder/src/server.rs +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -33,9 +33,9 @@ foreign_type! { pub struct RpcServerRef; } -/// SAFETY - The opaque handle can be cloned freely. +/// SAFETY: The opaque handle can be cloned freely. unsafe impl Send for RpcServer {} -/// SAFETY - The underlying C++ RpcServer class is thread-safe. +/// SAFETY: The underlying C++ RpcServer class is thread-safe. unsafe impl Sync for RpcServer {} impl RpcServer { @@ -59,7 +59,10 @@ impl RpcServer { /// Creates a binder RPC server, serving the supplied binder service implementation on the given /// socket file descriptor. The socket should be bound to an address before calling this /// function. - pub fn new_bound_socket(mut service: SpIBinder, socket_fd: OwnedFd) -> Result<RpcServer, Error> { + pub fn new_bound_socket( + mut service: SpIBinder, + socket_fd: OwnedFd, + ) -> Result<RpcServer, Error> { let service = service.as_native_mut(); // SAFETY: Service ownership is transferring to the server and won't be valid afterward. @@ -67,7 +70,8 @@ impl RpcServer { // The server takes ownership of the socket FD. unsafe { Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket( - service, socket_fd.into_raw_fd(), + service, + socket_fd.into_raw_fd(), )) } } @@ -120,7 +124,9 @@ impl RpcServer { if ptr.is_null() { return Err(Error::new(ErrorKind::Other, "Failed to start server")); } - Ok(RpcServer::from_ptr(ptr)) + // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not + // null. + Ok(unsafe { RpcServer::from_ptr(ptr) }) } } @@ -130,7 +136,7 @@ impl RpcServerRef { &self, modes: &[FileDescriptorTransportMode], ) { - // SAFETY - Does not keep the pointer after returning does, nor does it + // SAFETY: Does not keep the pointer after returning does, nor does it // read past its boundary. Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes( @@ -143,18 +149,21 @@ impl RpcServerRef { /// Starts a new background thread and calls join(). Returns immediately. pub fn start(&self) { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) }; } /// Joins the RpcServer thread. The call blocks until the server terminates. /// This must be called from exactly one thread. pub fn join(&self) { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) }; } /// Shuts down the running RpcServer. Can be called multiple times and from /// multiple threads. Called automatically during drop(). pub fn shutdown(&self) -> Result<(), Error> { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } { Ok(()) } else { diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs index 28c5390665..79a951073e 100644 --- a/libs/binder/rust/rpcbinder/src/session.rs +++ b/libs/binder/rust/rpcbinder/src/session.rs @@ -36,15 +36,15 @@ foreign_type! { pub struct RpcSessionRef; } -/// SAFETY - The opaque handle can be cloned freely. +/// SAFETY: The opaque handle can be cloned freely. unsafe impl Send for RpcSession {} -/// SAFETY - The underlying C++ RpcSession class is thread-safe. +/// SAFETY: The underlying C++ RpcSession class is thread-safe. unsafe impl Sync for RpcSession {} impl RpcSession { /// Allocates a new RpcSession object. pub fn new() -> RpcSession { - // SAFETY - Takes ownership of the returned handle, which has correct refcount. + // SAFETY: Takes ownership of the returned handle, which has correct refcount. unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) } } } @@ -58,7 +58,7 @@ impl Default for RpcSession { impl RpcSessionRef { /// Sets the file descriptor transport mode for this session. pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) { - // SAFETY - Only passes the 'self' pointer as an opaque handle. + // SAFETY: Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode( self.as_ptr(), @@ -69,7 +69,7 @@ impl RpcSessionRef { /// Sets the maximum number of incoming threads. pub fn set_max_incoming_threads(&self, threads: usize) { - // SAFETY - Only passes the 'self' pointer as an opaque handle. + // SAFETY: Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads) }; @@ -77,7 +77,7 @@ impl RpcSessionRef { /// Sets the maximum number of outgoing connections. pub fn set_max_outgoing_connections(&self, connections: usize) { - // SAFETY - Only passes the 'self' pointer as an opaque handle. + // SAFETY: Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections( self.as_ptr(), @@ -210,10 +210,10 @@ impl RpcSessionRef { type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>; unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int { + let request_fd_ptr = param as *mut RequestFd; // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the // BinderFdFactory reference, with param being a properly aligned non-null pointer to an // initialized instance. - let request_fd_ptr = param as *mut RequestFd; - let request_fd = request_fd_ptr.as_mut().unwrap(); + let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() }; request_fd().unwrap_or(-1) } diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 993bdca4a5..463c210316 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -97,8 +97,8 @@ where /// Interface stability promise /// -/// An interface can promise to be a stable vendor interface ([`Vintf`]), or -/// makes no stability guarantees ([`Local`]). [`Local`] is +/// An interface can promise to be a stable vendor interface ([`Stability::Vintf`]), +/// or makes no stability guarantees ([`Stability::Local`]). [`Stability::Local`] is /// currently the default stability. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum Stability { @@ -139,8 +139,8 @@ impl TryFrom<i32> for Stability { /// via `Binder::new(object)`. /// /// This is a low-level interface that should normally be automatically -/// generated from AIDL via the [`declare_binder_interface!`] macro. When using -/// the AIDL backend, users need only implement the high-level AIDL-defined +/// generated from AIDL via the [`crate::declare_binder_interface!`] macro. +/// When using the AIDL backend, users need only implement the high-level AIDL-defined /// interface. The AIDL compiler then generates a container struct that wraps /// the user-defined service and implements `Remotable`. pub trait Remotable: Send + Sync { @@ -297,18 +297,17 @@ impl InterfaceClass { /// Note: the returned pointer will not be constant. Calling this method /// multiple times for the same type will result in distinct class /// pointers. A static getter for this value is implemented in - /// [`declare_binder_interface!`]. + /// [`crate::declare_binder_interface!`]. pub fn new<I: InterfaceClassMethods>() -> InterfaceClass { let descriptor = CString::new(I::get_descriptor()).unwrap(); + // Safety: `AIBinder_Class_define` expects a valid C string, and three + // valid callback functions, all non-null pointers. The C string is + // copied and need not be valid for longer than the call, so we can drop + // it after the call. We can safely assign null to the onDump and + // handleShellCommand callbacks as long as the class pointer was + // non-null. Rust None for a Option<fn> is guaranteed to be a NULL + // pointer. Rust retains ownership of the pointer after it is defined. let ptr = unsafe { - // Safety: `AIBinder_Class_define` expects a valid C string, and - // three valid callback functions, all non-null pointers. The C - // string is copied and need not be valid for longer than the call, - // so we can drop it after the call. We can safely assign null to - // the onDump and handleShellCommand callbacks as long as the class - // pointer was non-null. Rust None for a Option<fn> is guaranteed to - // be a NULL pointer. Rust retains ownership of the pointer after it - // is defined. let class = sys::AIBinder_Class_define( descriptor.as_ptr(), Some(I::on_create), @@ -338,13 +337,12 @@ impl InterfaceClass { /// Get the interface descriptor string of this class. pub fn get_descriptor(&self) -> String { + // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor is + // always a two-byte null terminated sequence of u16s. Thus, we can + // continue reading from the pointer until we hit a null value, and this + // pointer can be a valid slice if the slice length is <= the number of + // u16 elements before the null terminator. unsafe { - // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor - // is always a two-byte null terminated sequence of u16s. Thus, we - // can continue reading from the pointer until we hit a null value, - // and this pointer can be a valid slice if the slice length is <= - // the number of u16 elements before the null terminator. - let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0); CStr::from_ptr(raw_descriptor) .to_str() @@ -542,17 +540,15 @@ macro_rules! binder_fn_get_class { static CLASS_INIT: std::sync::Once = std::sync::Once::new(); static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None; + // Safety: This assignment is guarded by the `CLASS_INIT` `Once` + // variable, and therefore is thread-safe, as it can only occur + // once. CLASS_INIT.call_once(|| unsafe { - // Safety: This assignment is guarded by the `CLASS_INIT` `Once` - // variable, and therefore is thread-safe, as it can only occur - // once. CLASS = Some($constructor); }); - unsafe { - // Safety: The `CLASS` variable can only be mutated once, above, - // and is subsequently safe to read from any thread. - CLASS.unwrap() - } + // Safety: The `CLASS` variable can only be mutated once, above, and + // is subsequently safe to read from any thread. + unsafe { CLASS.unwrap() } } }; } @@ -664,6 +660,8 @@ pub unsafe trait AsNative<T> { fn as_native_mut(&mut self) -> *mut T; } +// Safety: If V is a valid Android C++ type then we can either use that or a +// null pointer. unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> { fn as_native(&self) -> *const T { self.as_ref().map_or(ptr::null(), |v| v.as_native()) @@ -924,15 +922,15 @@ macro_rules! declare_binder_interface { static CLASS_INIT: std::sync::Once = std::sync::Once::new(); static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None; + // Safety: This assignment is guarded by the `CLASS_INIT` `Once` + // variable, and therefore is thread-safe, as it can only occur + // once. CLASS_INIT.call_once(|| unsafe { - // Safety: This assignment is guarded by the `CLASS_INIT` `Once` - // variable, and therefore is thread-safe, as it can only occur - // once. CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>()); }); + // Safety: The `CLASS` variable can only be mutated once, above, + // and is subsequently safe to read from any thread. unsafe { - // Safety: The `CLASS` variable can only be mutated once, above, - // and is subsequently safe to read from any thread. CLASS.unwrap() } } @@ -1025,17 +1023,7 @@ 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()); - if let Ok(service) = service { - // We were able to associate with our expected class and - // the service is local. - todo!() - //return Ok($crate::Strong::new(Box::new(service))); - } else { - // Service is remote - return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); - } + return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); } Err($crate::StatusCode::BAD_TYPE.into()) diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs index ba260624bc..eb04cc3153 100644 --- a/libs/binder/rust/src/error.rs +++ b/libs/binder/rust/src/error.rs @@ -112,41 +112,35 @@ fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> { impl Status { /// Create a status object representing a successful transaction. pub fn ok() -> Self { - let ptr = unsafe { - // Safety: `AStatus_newOk` always returns a new, heap allocated - // pointer to an `ASTatus` object, so we know this pointer will be - // valid. - // - // Rust takes ownership of the returned pointer. - sys::AStatus_newOk() - }; + // Safety: `AStatus_newOk` always returns a new, heap allocated + // pointer to an `ASTatus` object, so we know this pointer will be + // valid. + // + // Rust takes ownership of the returned pointer. + let ptr = unsafe { sys::AStatus_newOk() }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } /// Create a status object from a service specific error pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status { let ptr = if let Some(message) = message { - unsafe { - // Safety: Any i32 is a valid service specific error for the - // error code parameter. We construct a valid, null-terminated - // `CString` from the message, which must be a valid C-style - // string to pass as the message. This function always returns a - // new, heap allocated pointer to an `AStatus` object, so we - // know the returned pointer will be valid. - // - // Rust takes ownership of the returned pointer. - sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) - } + // Safety: Any i32 is a valid service specific error for the + // error code parameter. We construct a valid, null-terminated + // `CString` from the message, which must be a valid C-style + // string to pass as the message. This function always returns a + // new, heap allocated pointer to an `AStatus` object, so we + // know the returned pointer will be valid. + // + // Rust takes ownership of the returned pointer. + unsafe { sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) } } else { - unsafe { - // Safety: Any i32 is a valid service specific error for the - // error code parameter. This function always returns a new, - // heap allocated pointer to an `AStatus` object, so we know the - // returned pointer will be valid. - // - // Rust takes ownership of the returned pointer. - sys::AStatus_fromServiceSpecificError(err) - } + // Safety: Any i32 is a valid service specific error for the + // error code parameter. This function always returns a new, + // heap allocated pointer to an `AStatus` object, so we know the + // returned pointer will be valid. + // + // Rust takes ownership of the returned pointer. + unsafe { sys::AStatus_fromServiceSpecificError(err) } }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } @@ -159,6 +153,8 @@ impl Status { /// Create a status object from an exception code pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status { if let Some(message) = message { + // Safety: the C string pointer is valid and not retained by the + // function. let ptr = unsafe { sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr()) }; @@ -187,37 +183,31 @@ impl Status { /// Returns `true` if this status represents a successful transaction. pub fn is_ok(&self) -> bool { - unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_isOk` here. - sys::AStatus_isOk(self.as_native()) - } + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_isOk` here. + unsafe { sys::AStatus_isOk(self.as_native()) } } /// Returns a description of the status. pub fn get_description(&self) -> String { - let description_ptr = unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_getDescription` - // here. - // - // `AStatus_getDescription` always returns a valid pointer to a null - // terminated C string. Rust is responsible for freeing this pointer - // via `AStatus_deleteDescription`. - sys::AStatus_getDescription(self.as_native()) - }; - let description = unsafe { - // Safety: `AStatus_getDescription` always returns a valid C string, - // which can be safely converted to a `CStr`. - CStr::from_ptr(description_ptr) - }; + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getDescription` + // here. + // + // `AStatus_getDescription` always returns a valid pointer to a null + // terminated C string. Rust is responsible for freeing this pointer + // via `AStatus_deleteDescription`. + let description_ptr = unsafe { sys::AStatus_getDescription(self.as_native()) }; + // Safety: `AStatus_getDescription` always returns a valid C string, + // which can be safely converted to a `CStr`. + let description = unsafe { CStr::from_ptr(description_ptr) }; let description = description.to_string_lossy().to_string(); + // Safety: `description_ptr` was returned from + // `AStatus_getDescription` above, and must be freed via + // `AStatus_deleteDescription`. We must not access the pointer after + // this call, so we copy it into an owned string above and return + // that string. unsafe { - // Safety: `description_ptr` was returned from - // `AStatus_getDescription` above, and must be freed via - // `AStatus_deleteDescription`. We must not access the pointer after - // this call, so we copy it into an owned string above and return - // that string. sys::AStatus_deleteDescription(description_ptr); } description @@ -225,12 +215,10 @@ impl Status { /// Returns the exception code of the status. pub fn exception_code(&self) -> ExceptionCode { - let code = unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_getExceptionCode` - // here. - sys::AStatus_getExceptionCode(self.as_native()) - }; + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getExceptionCode` + // here. + let code = unsafe { sys::AStatus_getExceptionCode(self.as_native()) }; parse_exception_code(code) } @@ -241,11 +229,9 @@ impl Status { /// exception or a service specific error. To find out if this transaction /// as a whole is okay, use [`is_ok`](Self::is_ok) instead. pub fn transaction_error(&self) -> StatusCode { - let code = unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_getStatus` here. - sys::AStatus_getStatus(self.as_native()) - }; + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getStatus` here. + let code = unsafe { sys::AStatus_getStatus(self.as_native()) }; parse_status_code(code) } @@ -258,12 +244,10 @@ impl Status { /// find out if this transaction as a whole is okay, use /// [`is_ok`](Self::is_ok) instead. pub fn service_specific_error(&self) -> i32 { - unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to - // `AStatus_getServiceSpecificError` here. - sys::AStatus_getServiceSpecificError(self.as_native()) - } + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to + // `AStatus_getServiceSpecificError` here. + unsafe { sys::AStatus_getServiceSpecificError(self.as_native()) } } /// Calls `op` if the status was ok, otherwise returns an `Err` value of @@ -321,24 +305,20 @@ impl From<StatusCode> for Status { impl From<status_t> for Status { fn from(status: status_t) -> Status { - let ptr = unsafe { - // Safety: `AStatus_fromStatus` expects any `status_t` integer, so - // this is a safe FFI call. Unknown values will be coerced into - // UNKNOWN_ERROR. - sys::AStatus_fromStatus(status) - }; + // Safety: `AStatus_fromStatus` expects any `status_t` integer, so + // this is a safe FFI call. Unknown values will be coerced into + // UNKNOWN_ERROR. + let ptr = unsafe { sys::AStatus_fromStatus(status) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } } impl From<ExceptionCode> for Status { fn from(code: ExceptionCode) -> Status { - let ptr = unsafe { - // Safety: `AStatus_fromExceptionCode` expects any - // `binder_exception_t` (i32) integer, so this is a safe FFI call. - // Unknown values will be coerced into EX_TRANSACTION_FAILED. - sys::AStatus_fromExceptionCode(code as i32) - }; + // Safety: `AStatus_fromExceptionCode` expects any + // `binder_exception_t` (i32) integer, so this is a safe FFI call. + // Unknown values will be coerced into EX_TRANSACTION_FAILED. + let ptr = unsafe { sys::AStatus_fromExceptionCode(code as i32) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } } @@ -363,20 +343,18 @@ impl From<Status> for status_t { impl Drop for Status { fn drop(&mut self) { + // Safety: `Status` manages the lifetime of its inner `AStatus` + // pointee, so we need to delete it here. We know that the pointer + // will be valid here since `Status` always contains a valid pointer + // while it is alive. unsafe { - // Safety: `Status` manages the lifetime of its inner `AStatus` - // pointee, so we need to delete it here. We know that the pointer - // will be valid here since `Status` always contains a valid pointer - // while it is alive. sys::AStatus_delete(self.0.as_mut()); } } } -/// # Safety -/// -/// `Status` always contains a valid pointer to an `AStatus` object, so we can -/// trivially convert it to a correctly-typed raw pointer. +/// Safety: `Status` always contains a valid pointer to an `AStatus` object, so +/// we can trivially convert it to a correctly-typed raw pointer. /// /// Care must be taken that the returned pointer is only dereferenced while the /// `Status` object is still alive. @@ -386,11 +364,97 @@ unsafe impl AsNative<sys::AStatus> for Status { } fn as_native_mut(&mut self) -> *mut sys::AStatus { - unsafe { - // Safety: The pointer will be valid here since `Status` always - // contains a valid and initialized pointer while it is alive. - self.0.as_mut() - } + // Safety: The pointer will be valid here since `Status` always contains + // a valid and initialized pointer while it is alive. + unsafe { self.0.as_mut() } + } +} + +/// A conversion from `std::result::Result<T, E>` to `binder::Result<T>`. If this type is `Ok(T)`, +/// it's returned as is. If this type is `Err(E)`, `E` is converted into `Status` which can be +/// either a general binder exception, or a service-specific exception. +/// +/// # Examples +/// +/// ``` +/// // std::io::Error is formatted as the exception's message +/// fn file_exists(name: &str) -> binder::Result<bool> { +/// std::fs::metadata(name) +/// .or_service_specific_exception(NOT_FOUND)? +/// } +/// +/// // A custom function is used to create the exception's message +/// fn file_exists(name: &str) -> binder::Result<bool> { +/// std::fs::metadata(name) +/// .or_service_specific_exception_with(NOT_FOUND, +/// |e| format!("file {} not found: {:?}", name, e))? +/// } +/// +/// // anyhow::Error is formatted as the exception's message +/// use anyhow::{Context, Result}; +/// fn file_exists(name: &str) -> binder::Result<bool> { +/// std::fs::metadata(name) +/// .context("file {} not found") +/// .or_service_specific_exception(NOT_FOUND)? +/// } +/// +/// // General binder exceptions can be created similarly +/// fn file_exists(name: &str) -> binder::Result<bool> { +/// std::fs::metadata(name) +/// .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)? +/// } +/// ``` +pub trait IntoBinderResult<T, E> { + /// Converts the embedded error into a general binder exception of code `exception`. The + /// message of the exception is set by formatting the error for debugging. + fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status>; + + /// Converts the embedded error into a general binder exception of code `exception`. The + /// message of the exception is set by lazily evaluating the `op` function. + fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>( + self, + exception: ExceptionCode, + op: O, + ) -> result::Result<T, Status>; + + /// Converts the embedded error into a service-specific binder exception. `error_code` is used + /// to distinguish different service-specific binder exceptions. The message of the exception + /// is set by formatting the error for debugging. + fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status>; + + /// Converts the embedded error into a service-specific binder exception. `error_code` is used + /// to distinguish different service-specific binder exceptions. The message of the exception + /// is set by lazily evaluating the `op` function. + fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>( + self, + error_code: i32, + op: O, + ) -> result::Result<T, Status>; +} + +impl<T, E: std::fmt::Debug> IntoBinderResult<T, E> for result::Result<T, E> { + fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status> { + self.or_binder_exception_with(exception, |e| format!("{:?}", e)) + } + + fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>( + self, + exception: ExceptionCode, + op: O, + ) -> result::Result<T, Status> { + self.map_err(|e| Status::new_exception_str(exception, Some(op(e)))) + } + + fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status> { + self.or_service_specific_exception_with(error_code, |e| format!("{:?}", e)) + } + + fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>( + self, + error_code: i32, + op: O, + ) -> result::Result<T, Status> { + self.map_err(|e| Status::new_service_specific_error_str(error_code, Some(op(e)))) } } @@ -430,4 +494,66 @@ mod tests { assert_eq!(status.service_specific_error(), 0); assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string()); } + + #[test] + fn convert_to_service_specific_exception() { + let res: std::result::Result<(), Status> = + Err("message").or_service_specific_exception(-42); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC); + assert_eq!(status.service_specific_error(), -42); + assert_eq!( + status.get_description(), + "Status(-8, EX_SERVICE_SPECIFIC): '-42: \"message\"'".to_string() + ); + } + + #[test] + fn convert_to_service_specific_exception_with() { + let res: std::result::Result<(), Status> = Err("message") + .or_service_specific_exception_with(-42, |e| format!("outer message: {:?}", e)); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC); + assert_eq!(status.service_specific_error(), -42); + assert_eq!( + status.get_description(), + "Status(-8, EX_SERVICE_SPECIFIC): '-42: outer message: \"message\"'".to_string() + ); + } + + #[test] + fn convert_to_binder_exception() { + let res: std::result::Result<(), Status> = + Err("message").or_binder_exception(ExceptionCode::ILLEGAL_STATE); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE); + assert_eq!(status.service_specific_error(), 0); + assert_eq!( + status.get_description(), + "Status(-5, EX_ILLEGAL_STATE): '\"message\"'".to_string() + ); + } + + #[test] + fn convert_to_binder_exception_with() { + let res: std::result::Result<(), Status> = Err("message") + .or_binder_exception_with(ExceptionCode::ILLEGAL_STATE, |e| { + format!("outer message: {:?}", e) + }); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE); + assert_eq!(status.service_specific_error(), 0); + assert_eq!( + status.get_description(), + "Status(-5, EX_ILLEGAL_STATE): 'outer message: \"message\"'".to_string() + ); + } } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 0c8b48f1f5..8841fe640b 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -106,7 +106,7 @@ use binder_ndk_sys as sys; pub use crate::binder_async::{BinderAsyncPool, BoxFuture}; pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak}; -pub use error::{ExceptionCode, Status, StatusCode}; +pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode}; pub use native::{ add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service, LazyServiceGuard, diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index 5557168055..b248f5eb28 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -42,7 +42,7 @@ pub struct Binder<T: Remotable> { rust_object: *mut T, } -/// # Safety +/// Safety: /// /// A `Binder<T>` is a pair of unique owning pointers to two values: /// * a C++ ABBinder which the C++ API guarantees can be passed between threads @@ -54,7 +54,7 @@ pub struct Binder<T: Remotable> { /// to how `Box<T>` is `Send` if `T` is `Send`. unsafe impl<T: Remotable> Send for Binder<T> {} -/// # Safety +/// Safety: /// /// A `Binder<T>` is a pair of unique owning pointers to two values: /// * a C++ ABBinder which is thread-safe, i.e. `Send + Sync` @@ -89,15 +89,13 @@ impl<T: Remotable> Binder<T> { pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> { let class = T::get_class(); let rust_object = Box::into_raw(Box::new(rust_object)); - let ibinder = unsafe { - // Safety: `AIBinder_new` expects a valid class pointer (which we - // initialize via `get_class`), and an arbitrary pointer - // argument. The caller owns the returned `AIBinder` pointer, which - // is a strong reference to a `BBinder`. This reference should be - // decremented via `AIBinder_decStrong` when the reference lifetime - // ends. - sys::AIBinder_new(class.into(), rust_object as *mut c_void) - }; + // Safety: `AIBinder_new` expects a valid class pointer (which we + // initialize via `get_class`), and an arbitrary pointer + // argument. The caller owns the returned `AIBinder` pointer, which + // is a strong reference to a `BBinder`. This reference should be + // decremented via `AIBinder_decStrong` when the reference lifetime + // ends. + let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) }; let mut binder = Binder { ibinder, rust_object }; binder.mark_stability(stability); binder @@ -176,15 +174,14 @@ impl<T: Remotable> Binder<T> { /// } /// # } pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> { - let status = unsafe { - // Safety: `AIBinder_setExtension` expects two valid, mutable - // `AIBinder` pointers. We are guaranteed that both `self` and - // `extension` contain valid `AIBinder` pointers, because they - // cannot be initialized without a valid - // pointer. `AIBinder_setExtension` does not take ownership of - // either parameter. - sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) - }; + let status = + // Safety: `AIBinder_setExtension` expects two valid, mutable + // `AIBinder` pointers. We are guaranteed that both `self` and + // `extension` contain valid `AIBinder` pointers, because they + // cannot be initialized without a valid + // pointer. `AIBinder_setExtension` does not take ownership of + // either parameter. + unsafe { sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) }; status_result(status) } @@ -199,9 +196,9 @@ impl<T: Remotable> Binder<T> { match stability { Stability::Local => self.mark_local_stability(), Stability::Vintf => { + // Safety: Self always contains a valid `AIBinder` pointer, so + // we can always call this C API safely. unsafe { - // Safety: Self always contains a valid `AIBinder` pointer, so - // we can always call this C API safely. sys::AIBinder_markVintfStability(self.as_native_mut()); } } @@ -212,9 +209,9 @@ impl<T: Remotable> Binder<T> { /// building for android_vendor and system otherwise. #[cfg(android_vendor)] fn mark_local_stability(&mut self) { + // Safety: Self always contains a valid `AIBinder` pointer, so we can + // always call this C API safely. unsafe { - // Safety: Self always contains a valid `AIBinder` pointer, so - // we can always call this C API safely. sys::AIBinder_markVendorStability(self.as_native_mut()); } } @@ -223,9 +220,9 @@ impl<T: Remotable> Binder<T> { /// building for android_vendor and system otherwise. #[cfg(not(android_vendor))] fn mark_local_stability(&mut self) { + // Safety: Self always contains a valid `AIBinder` pointer, so we can + // always call this C API safely. unsafe { - // Safety: Self always contains a valid `AIBinder` pointer, so - // we can always call this C API safely. sys::AIBinder_markSystemStability(self.as_native_mut()); } } @@ -239,13 +236,13 @@ impl<T: Remotable> Interface for Binder<T> { /// remotable object, which will prevent the object from being dropped while /// the `SpIBinder` is alive. fn as_binder(&self) -> SpIBinder { + // Safety: `self.ibinder` is guaranteed to always be a valid pointer + // to an `AIBinder` by the `Binder` constructor. We are creating a + // copy of the `self.ibinder` strong reference, but + // `SpIBinder::from_raw` assumes it receives an owned pointer with + // its own strong reference. We first increment the reference count, + // so that the new `SpIBinder` will be tracked as a new reference. unsafe { - // Safety: `self.ibinder` is guaranteed to always be a valid pointer - // to an `AIBinder` by the `Binder` constructor. We are creating a - // copy of the `self.ibinder` strong reference, but - // `SpIBinder::from_raw` assumes it receives an owned pointer with - // its own strong reference. We first increment the reference count, - // so that the new `SpIBinder` will be tracked as a new reference. sys::AIBinder_incStrong(self.ibinder); SpIBinder::from_raw(self.ibinder).unwrap() } @@ -275,10 +272,20 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> { reply: *mut sys::AParcel, ) -> status_t { let res = { - let mut reply = BorrowedParcel::from_raw(reply).unwrap(); - let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap(); - let object = sys::AIBinder_getUserData(binder); - let binder: &T = &*(object as *const T); + // Safety: The caller must give us a parcel pointer which is either + // null or valid at least for the duration of this function call. We + // don't keep the resulting value beyond the function. + let mut reply = unsafe { BorrowedParcel::from_raw(reply).unwrap() }; + // Safety: The caller must give us a parcel pointer which is either + // null or valid at least for the duration of this function call. We + // don't keep the resulting value beyond the function. + let data = unsafe { BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap() }; + // Safety: Our caller promised that `binder` is a non-null, valid + // pointer to a local `AIBinder`. + let object = unsafe { sys::AIBinder_getUserData(binder) }; + // Safety: Our caller promised that the binder has a `T` pointer in + // its user data. + let binder: &T = unsafe { &*(object as *const T) }; binder.on_transact(code, &data, &mut reply) }; match res { @@ -295,7 +302,9 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> { /// Must be called with a valid pointer to a `T` object. After this call, /// the pointer will be invalid and should not be dereferenced. unsafe extern "C" fn on_destroy(object: *mut c_void) { - drop(Box::from_raw(object as *mut T)); + // Safety: Our caller promised that `object` is a valid pointer to a + // `T`. + drop(unsafe { Box::from_raw(object as *mut T) }); } /// Called whenever a new, local `AIBinder` object is needed of a specific @@ -320,7 +329,7 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> { /// Must be called with a non-null, valid pointer to a local `AIBinder` that /// contains a `T` pointer in its user data. fd should be a non-owned file /// descriptor, and args must be an array of null-terminated string - /// poiinters with length num_args. + /// pointers with length num_args. unsafe extern "C" fn on_dump( binder: *mut sys::AIBinder, fd: i32, @@ -330,8 +339,9 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> { if fd < 0 { return StatusCode::UNEXPECTED_NULL as status_t; } - // We don't own this file, so we need to be careful not to drop it. - let file = ManuallyDrop::new(File::from_raw_fd(fd)); + // Safety: Our caller promised that fd is a file descriptor. We don't + // own this file descriptor, so we need to be careful not to drop it. + let file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd)) }; if args.is_null() && num_args != 0 { return StatusCode::UNEXPECTED_NULL as status_t; @@ -340,14 +350,22 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> { let args = if args.is_null() || num_args == 0 { vec![] } else { - slice::from_raw_parts(args, num_args as usize) - .iter() - .map(|s| CStr::from_ptr(*s)) - .collect() + // Safety: Our caller promised that `args` is an array of + // null-terminated string pointers with length `num_args`. + unsafe { + slice::from_raw_parts(args, num_args as usize) + .iter() + .map(|s| CStr::from_ptr(*s)) + .collect() + } }; - let object = sys::AIBinder_getUserData(binder); - let binder: &T = &*(object as *const T); + // Safety: Our caller promised that `binder` is a non-null, valid + // pointer to a local `AIBinder`. + let object = unsafe { sys::AIBinder_getUserData(binder) }; + // Safety: Our caller promised that the binder has a `T` pointer in its + // user data. + let binder: &T = unsafe { &*(object as *const T) }; let res = binder.on_dump(&file, &args); match res { @@ -363,11 +381,11 @@ impl<T: Remotable> Drop for Binder<T> { // actually destroys the object, it calls `on_destroy` and we can drop the // `rust_object` then. fn drop(&mut self) { + // Safety: When `self` is dropped, we can no longer access the + // reference, so can decrement the reference count. `self.ibinder` is + // always a valid `AIBinder` pointer, so is valid to pass to + // `AIBinder_decStrong`. unsafe { - // Safety: When `self` is dropped, we can no longer access the - // reference, so can decrement the reference count. `self.ibinder` - // is always a valid `AIBinder` pointer, so is valid to pass to - // `AIBinder_decStrong`. sys::AIBinder_decStrong(self.ibinder); } } @@ -377,14 +395,11 @@ impl<T: Remotable> Deref for Binder<T> { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { - // Safety: While `self` is alive, the reference count of the - // underlying object is > 0 and therefore `on_destroy` cannot be - // called. Therefore while `self` is alive, we know that - // `rust_object` is still a valid pointer to a heap allocated object - // of type `T`. - &*self.rust_object - } + // Safety: While `self` is alive, the reference count of the underlying + // object is > 0 and therefore `on_destroy` cannot be called. Therefore + // while `self` is alive, we know that `rust_object` is still a valid + // pointer to a heap allocated object of type `T`. + unsafe { &*self.rust_object } } } @@ -405,13 +420,10 @@ impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> { if Some(class) != ibinder.get_class() { return Err(StatusCode::BAD_TYPE); } - let userdata = unsafe { - // Safety: `SpIBinder` always holds a valid pointer pointer to an - // `AIBinder`, which we can safely pass to - // `AIBinder_getUserData`. `ibinder` retains ownership of the - // returned pointer. - sys::AIBinder_getUserData(ibinder.as_native_mut()) - }; + // Safety: `SpIBinder` always holds a valid pointer pointer to an + // `AIBinder`, which we can safely pass to `AIBinder_getUserData`. + // `ibinder` retains ownership of the returned pointer. + let userdata = unsafe { sys::AIBinder_getUserData(ibinder.as_native_mut()) }; if userdata.is_null() { return Err(StatusCode::UNEXPECTED_NULL); } @@ -422,12 +434,10 @@ impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> { } } -/// # Safety -/// -/// The constructor for `Binder` guarantees that `self.ibinder` will contain a -/// valid, non-null pointer to an `AIBinder`, so this implementation is type -/// safe. `self.ibinder` will remain valid for the entire lifetime of `self` -/// because we hold a strong reference to the `AIBinder` until `self` is +/// Safety: The constructor for `Binder` guarantees that `self.ibinder` will +/// contain a valid, non-null pointer to an `AIBinder`, so this implementation +/// is type safe. `self.ibinder` will remain valid for the entire lifetime of +/// `self` because we hold a strong reference to the `AIBinder` until `self` is /// dropped. unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> { fn as_native(&self) -> *const sys::AIBinder { @@ -447,14 +457,12 @@ unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> { /// This function will panic if the identifier contains a 0 byte (NUL). pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { let instance = CString::new(identifier).unwrap(); - let status = unsafe { - // Safety: `AServiceManager_addService` expects valid `AIBinder` and C - // string pointers. Caller retains ownership of both - // pointers. `AServiceManager_addService` creates a new strong reference - // and copies the string, so both pointers need only be valid until the - // call returns. - sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) - }; + let status = + // Safety: `AServiceManager_addService` expects valid `AIBinder` and C + // string pointers. Caller retains ownership of both pointers. + // `AServiceManager_addService` creates a new strong reference and copies + // the string, so both pointers need only be valid until the call returns. + unsafe { sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) }; status_result(status) } @@ -470,13 +478,12 @@ pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { /// This function will panic if the identifier contains a 0 byte (NUL). pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { let instance = CString::new(identifier).unwrap(); + // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C + // string pointers. Caller retains ownership of both + // pointers. `AServiceManager_registerLazyService` creates a new strong reference + // and copies the string, so both pointers need only be valid until the + // call returns. let status = unsafe { - // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C - // string pointers. Caller retains ownership of both - // pointers. `AServiceManager_registerLazyService` creates a new strong reference - // and copies the string, so both pointers need only be valid until the - // call returns. - sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr()) }; status_result(status) @@ -491,10 +498,8 @@ pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result< /// /// Consider using [`LazyServiceGuard`] rather than calling this directly. pub fn force_lazy_services_persist(persist: bool) { - unsafe { - // Safety: No borrowing or transfer of ownership occurs here. - sys::AServiceManager_forceLazyServicesPersist(persist) - } + // Safety: No borrowing or transfer of ownership occurs here. + unsafe { sys::AServiceManager_forceLazyServicesPersist(persist) } } /// An RAII object to ensure a process which registers lazy services is not killed. During the @@ -576,8 +581,6 @@ impl Interface for () {} /// Determine whether the current thread is currently executing an incoming /// transaction. pub fn is_handling_transaction() -> bool { - unsafe { - // Safety: This method is always safe to call. - sys::AIBinder_isHandlingTransaction() - } + // Safety: This method is always safe to call. + unsafe { sys::AIBinder_isHandlingTransaction() } } diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index e4c568eab2..3c615edbc0 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -52,11 +52,8 @@ pub struct Parcel { ptr: NonNull<sys::AParcel>, } -/// # Safety -/// -/// This type guarantees that it owns the AParcel and that all access to -/// the AParcel happens through the Parcel, so it is ok to send across -/// threads. +/// Safety: This type guarantees that it owns the AParcel and that all access to +/// the AParcel happens through the Parcel, so it is ok to send across threads. unsafe impl Send for Parcel {} /// Container for a message (data and object references) that can be sent @@ -73,11 +70,9 @@ pub struct BorrowedParcel<'a> { impl Parcel { /// Create a new empty `Parcel`. pub fn new() -> Parcel { - let ptr = unsafe { - // Safety: If `AParcel_create` succeeds, it always returns - // a valid pointer. If it fails, the process will crash. - sys::AParcel_create() - }; + // Safety: If `AParcel_create` succeeds, it always returns + // a valid pointer. If it fails, the process will crash. + let ptr = unsafe { sys::AParcel_create() }; Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") } } @@ -171,10 +166,8 @@ impl<'a> BorrowedParcel<'a> { } } -/// # Safety -/// -/// The `Parcel` constructors guarantee that a `Parcel` object will always -/// contain a valid pointer to an `AParcel`. +/// Safety: The `Parcel` constructors guarantee that a `Parcel` object will +/// always contain a valid pointer to an `AParcel`. unsafe impl AsNative<sys::AParcel> for Parcel { fn as_native(&self) -> *const sys::AParcel { self.ptr.as_ptr() @@ -185,10 +178,8 @@ unsafe impl AsNative<sys::AParcel> for Parcel { } } -/// # Safety -/// -/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object -/// will always contain a valid pointer to an `AParcel`. +/// Safety: The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` +/// object will always contain a valid pointer to an `AParcel`. unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> { fn as_native(&self) -> *const sys::AParcel { self.ptr.as_ptr() @@ -203,10 +194,8 @@ unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> { impl<'a> BorrowedParcel<'a> { /// Data written to parcelable is zero'd before being deleted or reallocated. pub fn mark_sensitive(&mut self) { - unsafe { - // Safety: guaranteed to have a parcel object, and this method never fails - sys::AParcel_markSensitive(self.as_native()) - } + // Safety: guaranteed to have a parcel object, and this method never fails + unsafe { sys::AParcel_markSensitive(self.as_native()) } } /// Write a type that implements [`Serialize`] to the parcel. @@ -265,11 +254,15 @@ impl<'a> BorrowedParcel<'a> { f(&mut subparcel)?; } let end = self.get_data_position(); + // Safety: start is less than the current size of the parcel data + // buffer, because we just got it with `get_data_position`. unsafe { self.set_data_position(start)?; } assert!(end >= start); self.write(&(end - start))?; + // Safety: end is less than the current size of the parcel data + // buffer, because we just got it with `get_data_position`. unsafe { self.set_data_position(end)?; } @@ -278,20 +271,16 @@ impl<'a> BorrowedParcel<'a> { /// Returns the current position in the parcel data. pub fn get_data_position(&self) -> i32 { - unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`, and this call is otherwise safe. - sys::AParcel_getDataPosition(self.as_native()) - } + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`, and this call is otherwise safe. + unsafe { sys::AParcel_getDataPosition(self.as_native()) } } /// Returns the total size of the parcel. pub fn get_data_size(&self) -> i32 { - unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`, and this call is otherwise safe. - sys::AParcel_getDataSize(self.as_native()) - } + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`, and this call is otherwise safe. + unsafe { sys::AParcel_getDataSize(self.as_native()) } } /// Move the current read/write position in the parcel. @@ -304,7 +293,9 @@ impl<'a> BorrowedParcel<'a> { /// accesses are bounds checked, this call is still safe, but we can't rely /// on that. pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> { - status_result(sys::AParcel_setDataPosition(self.as_native(), pos)) + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`, and the caller guarantees that `pos` is within bounds. + status_result(unsafe { sys::AParcel_setDataPosition(self.as_native(), pos) }) } /// Append a subset of another parcel. @@ -317,10 +308,10 @@ impl<'a> BorrowedParcel<'a> { start: i32, size: i32, ) -> Result<()> { + // Safety: `Parcel::appendFrom` from C++ checks that `start` + // and `size` are in bounds, and returns an error otherwise. + // Both `self` and `other` always contain valid pointers. let status = unsafe { - // Safety: `Parcel::appendFrom` from C++ checks that `start` - // and `size` are in bounds, and returns an error otherwise. - // Both `self` and `other` always contain valid pointers. sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size) }; status_result(status) @@ -418,7 +409,9 @@ impl Parcel { /// accesses are bounds checked, this call is still safe, but we can't rely /// on that. pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> { - self.borrowed_ref().set_data_position(pos) + // Safety: We have the same safety requirements as + // `BorrowedParcel::set_data_position`. + unsafe { self.borrowed_ref().set_data_position(pos) } } /// Append a subset of another parcel. @@ -461,7 +454,7 @@ impl<'a> BorrowedParcel<'a> { /// and call a closure with the sub-parcel as its parameter. /// The closure can keep reading data from the sub-parcel /// until it runs out of input data. The closure is responsible - /// for calling [`ReadableSubParcel::has_more_data`] to check for + /// for calling `ReadableSubParcel::has_more_data` to check for /// more data before every read, at least until Rust generators /// are stabilized. /// After the closure returns, skip to the end of the current @@ -504,7 +497,10 @@ impl<'a> BorrowedParcel<'a> { f(subparcel)?; // Advance the data position to the actual end, - // in case the closure read less data than was available + // in case the closure read less data than was available. + // + // Safety: end must be less than the current size of the parcel, because + // we checked above against `get_data_size`. unsafe { self.set_data_position(end)?; } @@ -595,7 +591,7 @@ impl Parcel { /// and call a closure with the sub-parcel as its parameter. /// The closure can keep reading data from the sub-parcel /// until it runs out of input data. The closure is responsible - /// for calling [`ReadableSubParcel::has_more_data`] to check for + /// for calling `ReadableSubParcel::has_more_data` to check for /// more data before every read, at least until Rust generators /// are stabilized. /// After the closure returns, skip to the end of the current @@ -649,17 +645,17 @@ impl Parcel { // Internal APIs impl<'a> BorrowedParcel<'a> { pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> { + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return + // null or a valid pointer to an `AIBinder`, both of which are + // valid, safe inputs to `AParcel_writeStrongBinder`. + // + // This call does not take ownership of the binder. However, it does + // require a mutable pointer, which we cannot extract from an + // immutable reference, so we clone the binder, incrementing the + // refcount before the call. The refcount will be immediately + // decremented when this temporary is dropped. unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return - // null or a valid pointer to an `AIBinder`, both of which are - // valid, safe inputs to `AParcel_writeStrongBinder`. - // - // This call does not take ownership of the binder. However, it does - // require a mutable pointer, which we cannot extract from an - // immutable reference, so we clone the binder, incrementing the - // refcount before the call. The refcount will be immediately - // decremented when this temporary is dropped. status_result(sys::AParcel_writeStrongBinder( self.as_native_mut(), binder.cloned().as_native_mut(), @@ -669,33 +665,28 @@ impl<'a> BorrowedParcel<'a> { pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> { let mut binder = ptr::null_mut(); - let status = unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`. We pass a valid, mutable out pointer to the `binder` - // parameter. After this call, `binder` will be either null or a - // valid pointer to an `AIBinder` owned by the caller. - sys::AParcel_readStrongBinder(self.as_native(), &mut binder) - }; + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`. We pass a valid, mutable out pointer to the `binder` + // parameter. After this call, `binder` will be either null or a + // valid pointer to an `AIBinder` owned by the caller. + let status = unsafe { sys::AParcel_readStrongBinder(self.as_native(), &mut binder) }; status_result(status)?; - Ok(unsafe { - // Safety: `binder` is either null or a valid, owned pointer at this - // point, so can be safely passed to `SpIBinder::from_raw`. - SpIBinder::from_raw(binder) - }) + // Safety: `binder` is either null or a valid, owned pointer at this + // point, so can be safely passed to `SpIBinder::from_raw`. + Ok(unsafe { SpIBinder::from_raw(binder) }) } } impl Drop for Parcel { fn drop(&mut self) { // Run the C++ Parcel complete object destructor - unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. Since we own the parcel, we can safely delete it - // here. - sys::AParcel_delete(self.ptr.as_ptr()) - } + // + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. Since we own the parcel, we can safely delete it + // here. + unsafe { sys::AParcel_delete(self.ptr.as_ptr()) } } } @@ -732,6 +723,8 @@ fn test_read_write() { parcel.write(&1i32).unwrap(); + // 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. unsafe { parcel.set_data_position(start).unwrap(); } @@ -748,6 +741,8 @@ fn test_read_data() { parcel.write(&b"Hello, Binder!\0"[..]).unwrap(); // Skip over string length + // SAFETY: str_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. unsafe { assert!(parcel.set_data_position(str_start).is_ok()); } @@ -756,42 +751,56 @@ fn test_read_data() { assert!(parcel.read::<bool>().unwrap()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<i8>().unwrap(), 72i8); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<u16>().unwrap(), 25928); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<i32>().unwrap(), 1819043144); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<u32>().unwrap(), 1819043144); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<i64>().unwrap(), 4764857262830019912); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<u64>().unwrap(), 4764857262830019912); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -799,6 +808,8 @@ fn test_read_data() { assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0); assert_eq!(parcel.read::<f32>().unwrap(), 40.043392); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -806,6 +817,8 @@ fn test_read_data() { assert_eq!(parcel.read::<f64>().unwrap(), 34732488246.197815); // Skip back to before the string length + // SAFETY: str_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. unsafe { assert!(parcel.set_data_position(str_start).is_ok()); } @@ -819,15 +832,21 @@ fn test_utf8_utf16_conversions() { let start = parcel.get_data_position(); assert!(parcel.write("Hello, Binder!").is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(parcel.write("Embedded null \0 inside a string").is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -835,6 +854,8 @@ fn test_utf8_utf16_conversions() { parcel.read::<Option<String>>().unwrap().unwrap(), "Embedded null \0 inside a string", ); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -849,6 +870,8 @@ fn test_utf8_utf16_conversions() { let s3 = "Some more text here."; assert!(parcel.write(&[s1, s2, s3][..]).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -874,6 +897,8 @@ fn test_sized_write() { assert_eq!(parcel.get_data_position(), start + expected_len); + // 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. unsafe { parcel.set_data_position(start).unwrap(); } @@ -893,6 +918,8 @@ fn test_append_from() { assert_eq!(4, parcel2.get_data_size()); assert_eq!(Ok(()), parcel2.append_all_from(&parcel1)); assert_eq!(8, parcel2.get_data_size()); + // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not + // empty. unsafe { parcel2.set_data_position(0).unwrap(); } @@ -903,6 +930,8 @@ fn test_append_from() { assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2)); assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2)); assert_eq!(4, parcel2.get_data_size()); + // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not + // empty. unsafe { parcel2.set_data_position(0).unwrap(); } @@ -911,6 +940,8 @@ fn test_append_from() { let mut parcel2 = Parcel::new(); assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2)); assert_eq!(2, parcel2.get_data_size()); + // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not + // empty. unsafe { parcel2.set_data_position(0).unwrap(); } diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs index 7fe37f3b68..5c688fa71b 100644 --- a/libs/binder/rust/src/parcel/file_descriptor.rs +++ b/libs/binder/rust/src/parcel/file_descriptor.rs @@ -73,14 +73,12 @@ impl Eq for ParcelFileDescriptor {} impl Serialize for ParcelFileDescriptor { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> { let fd = self.0.as_raw_fd(); - let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a - // valid file, so we can borrow a valid file - // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take - // ownership of the fd, so we need not duplicate it first. - sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) - }; + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a + // valid file, so we can borrow a valid file + // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take + // ownership of the fd, so we need not duplicate it first. + let status = unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) }; status_result(status) } } @@ -92,13 +90,12 @@ impl SerializeOption for ParcelFileDescriptor { if let Some(f) = this { f.serialize(parcel) } else { - let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the - // value `-1` as the file descriptor to signify serializing a - // null file descriptor. - sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) - }; + let status = + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the + // value `-1` as the file descriptor to signify serializing a + // null file descriptor. + unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) }; status_result(status) } } @@ -107,25 +104,23 @@ impl SerializeOption for ParcelFileDescriptor { impl DeserializeOption for ParcelFileDescriptor { fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> { let mut fd = -1i32; + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid mutable pointer to an i32, which + // `AParcel_readParcelFileDescriptor` assigns the valid file + // descriptor into, or `-1` if deserializing a null file + // descriptor. The read function passes ownership of the file + // descriptor to its caller if it was non-null, so we must take + // ownership of the file and ensure that it is eventually closed. unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. We pass a valid mutable pointer to an i32, which - // `AParcel_readParcelFileDescriptor` assigns the valid file - // descriptor into, or `-1` if deserializing a null file - // descriptor. The read function passes ownership of the file - // descriptor to its caller if it was non-null, so we must take - // ownership of the file and ensure that it is eventually closed. status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?; } if fd < 0 { Ok(None) } else { - let file = unsafe { - // Safety: At this point, we know that the file descriptor was - // not -1, so must be a valid, owned file descriptor which we - // can safely turn into a `File`. - File::from_raw_fd(fd) - }; + // Safety: At this point, we know that the file descriptor was + // not -1, so must be a valid, owned file descriptor which we + // can safely turn into a `File`. + let file = unsafe { File::from_raw_fd(fd) }; Ok(Some(ParcelFileDescriptor::new(file))) } } diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs index 5d8c11cf94..9008a3cc0e 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -50,14 +50,14 @@ pub trait Parcelable { fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>; } -/// A struct whose instances can be written to a [`Parcel`]. +/// A struct whose instances can be written to a [`crate::parcel::Parcel`]. // Might be able to hook this up as a serde backend in the future? pub trait Serialize { - /// Serialize this instance into the given [`Parcel`]. + /// Serialize this instance into the given [`crate::parcel::Parcel`]. fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>; } -/// A struct whose instances can be restored from a [`Parcel`]. +/// A struct whose instances can be restored from a [`crate::parcel::Parcel`]. // Might be able to hook this up as a serde backend in the future? pub trait Deserialize: Sized { /// Type for the uninitialized value of this type. Will be either `Self` @@ -80,10 +80,10 @@ pub trait Deserialize: Sized { /// Convert an initialized value of type `Self` into `Self::UninitType`. fn from_init(value: Self) -> Self::UninitType; - /// Deserialize an instance from the given [`Parcel`]. + /// Deserialize an instance from the given [`crate::parcel::Parcel`]. fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>; - /// Deserialize an instance from the given [`Parcel`] onto the + /// Deserialize an instance from the given [`crate::parcel::Parcel`] onto the /// current object. This operation will overwrite the old value /// partially or completely, depending on how much data is available. fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> { @@ -102,8 +102,8 @@ pub trait Deserialize: Sized { pub trait SerializeArray: Serialize + Sized { /// Serialize an array of this type into the given parcel. fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: Safe FFI, slice will always be a safe pointer to pass. let res = unsafe { - // Safety: Safe FFI, slice will always be a safe pointer to pass. sys::AParcel_writeParcelableArray( parcel.as_native_mut(), slice.as_ptr() as *const c_void, @@ -117,7 +117,9 @@ pub trait SerializeArray: Serialize + Sized { /// Callback to serialize an element of a generic parcelable array. /// -/// Safety: We are relying on binder_ndk to not overrun our slice. As long as it +/// # Safety +/// +/// We are relying on binder_ndk to not overrun our slice. As long as it /// doesn't provide an index larger than the length of the original slice in /// serialize_array, this operation is safe. The index provided is zero-based. unsafe extern "C" fn serialize_element<T: Serialize>( @@ -125,9 +127,14 @@ unsafe extern "C" fn serialize_element<T: Serialize>( array: *const c_void, index: usize, ) -> status_t { - let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1); - - let mut parcel = match BorrowedParcel::from_raw(parcel) { + // Safety: The caller guarantees that `array` is a valid pointer of the + // appropriate type. + let slice: &[T] = unsafe { slice::from_raw_parts(array.cast(), index + 1) }; + + // Safety: The caller must give us a parcel pointer which is either null or + // valid at least for the duration of this function call. We don't keep the + // resulting value beyond the function. + let mut parcel = match unsafe { BorrowedParcel::from_raw(parcel) } { None => return StatusCode::UNEXPECTED_NULL as status_t, Some(p) => p, }; @@ -142,9 +149,9 @@ pub trait DeserializeArray: Deserialize { /// Deserialize an array of type from the given parcel. fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> { let mut vec: Option<Vec<Self::UninitType>> = None; + // Safety: Safe FFI, vec is the correct opaque type expected by + // allocate_vec and deserialize_element. let res = unsafe { - // Safety: Safe FFI, vec is the correct opaque type expected by - // allocate_vec and deserialize_element. sys::AParcel_readParcelableArray( parcel.as_native(), &mut vec as *mut _ as *mut c_void, @@ -153,21 +160,21 @@ pub trait DeserializeArray: Deserialize { ) }; status_result(res)?; - let vec: Option<Vec<Self>> = unsafe { - // Safety: We are assuming that the NDK correctly initialized every - // element of the vector by now, so we know that all the - // UninitTypes are now properly initialized. We can transmute from - // Vec<T::UninitType> to Vec<T> because T::UninitType has the same - // alignment and size as T, so the pointer to the vector allocation - // will be compatible. - mem::transmute(vec) - }; + // Safety: We are assuming that the NDK correctly initialized every + // element of the vector by now, so we know that all the + // UninitTypes are now properly initialized. We can transmute from + // Vec<T::UninitType> to Vec<T> because T::UninitType has the same + // alignment and size as T, so the pointer to the vector allocation + // will be compatible. + let vec: Option<Vec<Self>> = unsafe { mem::transmute(vec) }; Ok(vec) } } /// Callback to deserialize a parcelable element. /// +/// # Safety +/// /// The opaque array data pointer must be a mutable pointer to an /// `Option<Vec<T::UninitType>>` with at least enough elements for `index` to be valid /// (zero-based). @@ -176,13 +183,18 @@ unsafe extern "C" fn deserialize_element<T: Deserialize>( array: *mut c_void, index: usize, ) -> status_t { - let vec = &mut *(array as *mut Option<Vec<T::UninitType>>); + // Safety: The caller guarantees that `array` is a valid pointer of the + // appropriate type. + let vec = unsafe { &mut *(array as *mut Option<Vec<T::UninitType>>) }; let vec = match vec { Some(v) => v, None => return StatusCode::BAD_INDEX as status_t, }; - let parcel = match BorrowedParcel::from_raw(parcel as *mut _) { + // Safety: The caller must give us a parcel pointer which is either null or + // valid at least for the duration of this function call. We don't keep the + // resulting value beyond the function. + let parcel = match unsafe { BorrowedParcel::from_raw(parcel as *mut _) } { None => return StatusCode::UNEXPECTED_NULL as status_t, Some(p) => p, }; @@ -254,16 +266,21 @@ pub trait DeserializeOption: Deserialize { /// /// The opaque data pointer passed to the array read function must be a mutable /// pointer to an `Option<Vec<T::UninitType>>`. `buffer` will be assigned a mutable pointer -/// to the allocated vector data if this function returns true. +/// to the allocated vector data if this function returns true. `buffer` must be a valid pointer. unsafe extern "C" fn allocate_vec_with_buffer<T: Deserialize>( data: *mut c_void, len: i32, buffer: *mut *mut T, ) -> bool { - let res = allocate_vec::<T>(data, len); - let vec = &mut *(data as *mut Option<Vec<T::UninitType>>); + // Safety: We have the same safety requirements as `allocate_vec` for `data`. + let res = unsafe { allocate_vec::<T>(data, len) }; + // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type. + let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) }; if let Some(new_vec) = vec { - *buffer = new_vec.as_mut_ptr() as *mut T; + // Safety: The caller guarantees that `buffer` is a valid pointer. + unsafe { + *buffer = new_vec.as_mut_ptr() as *mut T; + } } res } @@ -275,7 +292,8 @@ unsafe extern "C" fn allocate_vec_with_buffer<T: Deserialize>( /// The opaque data pointer passed to the array read function must be a mutable /// pointer to an `Option<Vec<T::UninitType>>`. unsafe extern "C" fn allocate_vec<T: Deserialize>(data: *mut c_void, len: i32) -> bool { - let vec = &mut *(data as *mut Option<Vec<T::UninitType>>); + // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type. + let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) }; if len < 0 { *vec = None; return true; @@ -286,7 +304,10 @@ unsafe extern "C" fn allocate_vec<T: Deserialize>(data: *mut c_void, len: i32) - let mut new_vec: Vec<T::UninitType> = Vec::with_capacity(len as usize); new_vec.resize_with(len as usize, T::uninit); - ptr::write(vec, Some(new_vec)); + // Safety: The caller guarantees that vec is a valid mutable pointer to the appropriate type. + unsafe { + ptr::write(vec, Some(new_vec)); + } true } @@ -305,21 +326,21 @@ unsafe fn vec_assume_init<T: Deserialize>(vec: Vec<T::UninitType>) -> Vec<T> { // Assert at compile time that `T` and `T::UninitType` have the same size and alignment. let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT; - // We can convert from Vec<T::UninitType> to Vec<T> because T::UninitType - // has the same alignment and size as T, so the pointer to the vector - // allocation will be compatible. let mut vec = ManuallyDrop::new(vec); - Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) + // Safety: We can convert from Vec<T::UninitType> to Vec<T> because + // T::UninitType has the same alignment and size as T, so the pointer to the + // vector allocation will be compatible. + unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) } } macro_rules! impl_parcelable { {Serialize, $ty:ty, $write_fn:path} => { impl Serialize for $ty { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`, and any `$ty` literal value is safe to pass to + // `$write_fn`. unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`, and any `$ty` literal value is safe to pass to - // `$write_fn`. status_result($write_fn(parcel.as_native_mut(), *self)) } } @@ -333,11 +354,11 @@ macro_rules! impl_parcelable { fn from_init(value: Self) -> Self::UninitType { value } fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> { let mut val = Self::default(); + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid, mutable pointer to `val`, a + // literal of type `$ty`, and `$read_fn` will write the + // value read into `val` if successful unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. We pass a valid, mutable pointer to `val`, a - // literal of type `$ty`, and `$read_fn` will write the - // value read into `val` if successful status_result($read_fn(parcel.as_native(), &mut val))? }; Ok(val) @@ -348,13 +369,13 @@ macro_rules! impl_parcelable { {SerializeArray, $ty:ty, $write_array_fn:path} => { impl SerializeArray for $ty { fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` + // will be a valid pointer to an array of elements of type + // `$ty`. If the slice length is 0, `slice.as_ptr()` may be + // dangling, but this is safe since the pointer is not + // dereferenced if the length parameter is 0. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` - // will be a valid pointer to an array of elements of type - // `$ty`. If the slice length is 0, `slice.as_ptr()` may be - // dangling, but this is safe since the pointer is not - // dereferenced if the length parameter is 0. $write_array_fn( parcel.as_native_mut(), slice.as_ptr(), @@ -373,11 +394,11 @@ macro_rules! impl_parcelable { impl DeserializeArray for $ty { fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> { let mut vec: Option<Vec<Self::UninitType>> = None; + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `allocate_vec<T>` expects the opaque pointer to + // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is + // correct for it. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. `allocate_vec<T>` expects the opaque pointer to - // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is - // correct for it. $read_array_fn( parcel.as_native(), &mut vec as *mut _ as *mut c_void, @@ -385,11 +406,11 @@ macro_rules! impl_parcelable { ) }; status_result(status)?; + // Safety: We are assuming that the NDK correctly + // initialized every element of the vector by now, so we + // know that all the UninitTypes are now properly + // initialized. let vec: Option<Vec<Self>> = unsafe { - // Safety: We are assuming that the NDK correctly - // initialized every element of the vector by now, so we - // know that all the UninitTypes are now properly - // initialized. vec.map(|vec| vec_assume_init(vec)) }; Ok(vec) @@ -479,13 +500,13 @@ impl Deserialize for u8 { impl SerializeArray for u8 { fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a + // valid pointer to an array of elements of type `$ty`. If the slice + // length is 0, `slice.as_ptr()` may be dangling, but this is safe + // since the pointer is not dereferenced if the length parameter is + // 0. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a - // valid pointer to an array of elements of type `$ty`. If the slice - // length is 0, `slice.as_ptr()` may be dangling, but this is safe - // since the pointer is not dereferenced if the length parameter is - // 0. sys::AParcel_writeByteArray( parcel.as_native_mut(), slice.as_ptr() as *const i8, @@ -518,13 +539,13 @@ impl Deserialize for i16 { impl SerializeArray for i16 { fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a + // valid pointer to an array of elements of type `$ty`. If the slice + // length is 0, `slice.as_ptr()` may be dangling, but this is safe + // since the pointer is not dereferenced if the length parameter is + // 0. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a - // valid pointer to an array of elements of type `$ty`. If the slice - // length is 0, `slice.as_ptr()` may be dangling, but this is safe - // since the pointer is not dereferenced if the length parameter is - // 0. sys::AParcel_writeCharArray( parcel.as_native_mut(), slice.as_ptr() as *const u16, @@ -538,22 +559,22 @@ impl SerializeArray for i16 { impl SerializeOption for str { fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> { match this { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the string pointer is null, + // `AParcel_writeString` requires that the length is -1 to + // indicate that we want to serialize a null string. None => unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the string pointer is null, - // `AParcel_writeString` requires that the length is -1 to - // indicate that we want to serialize a null string. status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1)) }, + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8 + // string pointer of `length` bytes, which is what str in Rust + // is. The docstring for `AParcel_writeString` says that the + // string input should be null-terminated, but it doesn't + // actually rely on that fact in the code. If this ever becomes + // necessary, we will need to null-terminate the str buffer + // before sending it. Some(s) => unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8 - // string pointer of `length` bytes, which is what str in Rust - // is. The docstring for `AParcel_writeString` says that the - // string input should be null-terminated, but it doesn't - // actually rely on that fact in the code. If this ever becomes - // necessary, we will need to null-terminate the str buffer - // before sending it. status_result(sys::AParcel_writeString( parcel.as_native_mut(), s.as_ptr() as *const c_char, @@ -597,11 +618,11 @@ impl Deserialize for Option<String> { fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> { let mut vec: Option<Vec<u8>> = None; + // Safety: `Parcel` always contains a valid pointer to an `AParcel`. + // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>` + // for `allocate_vec`, so `vec` is safe to pass as the opaque data + // pointer on platforms where char is signed. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an `AParcel`. - // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>` - // for `allocate_vec`, so `vec` is safe to pass as the opaque data - // pointer on platforms where char is signed. sys::AParcel_readString( parcel.as_native(), &mut vec as *mut _ as *mut c_void, @@ -751,11 +772,11 @@ impl Deserialize for Stability { impl Serialize for Status { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an `AParcel` + // and `Status` always contains a valid pointer to an `AStatus`, so + // both parameters are valid and safe. This call does not take + // ownership of either of its parameters. unsafe { - // Safety: `Parcel` always contains a valid pointer to an `AParcel` - // and `Status` always contains a valid pointer to an `AStatus`, so - // both parameters are valid and safe. This call does not take - // ownership of either of its parameters. status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native())) } } @@ -772,21 +793,18 @@ impl Deserialize for Status { fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> { let mut status_ptr = ptr::null_mut(); - let ret_status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. We pass a mutable out pointer which will be - // assigned a valid `AStatus` pointer if the function returns - // status OK. This function passes ownership of the status - // pointer to the caller, if it was assigned. - sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) - }; + let ret_status = + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a mutable out pointer which will be + // assigned a valid `AStatus` pointer if the function returns + // status OK. This function passes ownership of the status + // pointer to the caller, if it was assigned. + unsafe { sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) }; status_result(ret_status)?; - Ok(unsafe { - // Safety: At this point, the return status of the read call was ok, - // so we know that `status_ptr` is a valid, owned pointer to an - // `AStatus`, from which we can safely construct a `Status` object. - Status::from_ptr(status_ptr) - }) + // Safety: At this point, the return status of the read call was ok, + // so we know that `status_ptr` is a valid, owned pointer to an + // `AStatus`, from which we can safely construct a `Status` object. + Ok(unsafe { Status::from_ptr(status_ptr) }) } } @@ -880,7 +898,6 @@ impl<T: DeserializeOption> Deserialize for Option<T> { /// `Serialize`, `SerializeArray` and `SerializeOption` for /// structured parcelables. The target type must implement the /// `Parcelable` trait. -/// ``` #[macro_export] macro_rules! impl_serialize_for_parcelable { ($parcelable:ident) => { @@ -1070,6 +1087,8 @@ mod tests { assert!(custom.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1092,6 +1111,8 @@ mod tests { assert!(bools.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1101,6 +1122,8 @@ mod tests { assert_eq!(parcel.read::<u32>().unwrap(), 0); assert_eq!(parcel.read::<u32>().unwrap(), 0); assert_eq!(parcel.read::<u32>().unwrap(), 1); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1116,12 +1139,17 @@ mod tests { assert!(parcel.write(&u8s[..]).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes + + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1131,18 +1159,25 @@ mod tests { let i8s = [-128i8, 127, 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(parcel.write(&i8s[..]).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes + + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1152,10 +1187,14 @@ mod tests { let u16s = [u16::max_value(), 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(u16s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1165,6 +1204,9 @@ mod tests { assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345 assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 assert_eq!(parcel.read::<u32>().unwrap(), 117); // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1175,10 +1217,14 @@ mod tests { let i16s = [i16::max_value(), i16::min_value(), 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(i16s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1188,6 +1234,9 @@ mod tests { assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value() assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1198,10 +1247,14 @@ mod tests { let u32s = [u32::max_value(), 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(u32s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1211,6 +1264,9 @@ mod tests { assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345 assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 assert_eq!(parcel.read::<u32>().unwrap(), 117); // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1221,10 +1277,14 @@ mod tests { let i32s = [i32::max_value(), i32::min_value(), 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(i32s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1234,6 +1294,9 @@ mod tests { assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value() assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1244,10 +1307,14 @@ mod tests { let u64s = [u64::max_value(), 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(u64s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1258,10 +1325,14 @@ mod tests { let i64s = [i64::max_value(), i64::min_value(), 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(i64s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1272,10 +1343,14 @@ mod tests { let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(f32s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1288,10 +1363,14 @@ mod tests { let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(f64s.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1309,10 +1388,14 @@ mod tests { let strs = [s1, s2, s3, s4]; + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(strs.serialize(&mut parcel.borrowed()).is_ok()); + // 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. unsafe { assert!(parcel.set_data_position(start).is_ok()); } diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs index eb82fb7fd6..f90611361f 100644 --- a/libs/binder/rust/src/parcel/parcelable_holder.rs +++ b/libs/binder/rust/src/parcel/parcelable_holder.rs @@ -133,8 +133,8 @@ impl ParcelableHolder { } } ParcelableHolderData::Parcel(ref mut parcel) => { + // Safety: 0 should always be a valid position. unsafe { - // Safety: 0 should always be a valid position. parcel.set_data_position(0)?; } @@ -214,15 +214,15 @@ impl Parcelable for ParcelableHolder { parcelable.write_to_parcel(parcel)?; let end = parcel.get_data_position(); + // Safety: we got the position from `get_data_position`. unsafe { - // Safety: we got the position from `get_data_position`. parcel.set_data_position(length_start)?; } assert!(end >= data_start); parcel.write(&(end - data_start))?; + // Safety: we got the position from `get_data_position`. unsafe { - // Safety: we got the position from `get_data_position`. parcel.set_data_position(end)?; } @@ -260,11 +260,11 @@ impl Parcelable for ParcelableHolder { new_parcel.append_from(parcel, data_start, data_size)?; *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel); + // Safety: `append_from` checks if `data_size` overflows + // `parcel` and returns `BAD_VALUE` if that happens. We also + // explicitly check for negative and zero `data_size` above, + // so `data_end` is guaranteed to be greater than `data_start`. unsafe { - // Safety: `append_from` checks if `data_size` overflows - // `parcel` and returns `BAD_VALUE` if that happens. We also - // explicitly check for negative and zero `data_size` above, - // so `data_end` is guaranteed to be greater than `data_start`. parcel.set_data_position(data_end)?; } diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index 036f6b4f01..dad3379bdc 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -49,14 +49,12 @@ impl fmt::Debug for SpIBinder { } } -/// # Safety -/// -/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe +/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Send for SpIBinder {} -/// # Safety -/// -/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe +/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Sync for SpIBinder {} impl SpIBinder { @@ -97,11 +95,9 @@ impl SpIBinder { /// Return true if this binder object is hosted in a different process than /// the current one. pub fn is_remote(&self) -> bool { - unsafe { - // Safety: `SpIBinder` guarantees that it always contains a valid - // `AIBinder` pointer. - sys::AIBinder_isRemote(self.as_native()) - } + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. + unsafe { sys::AIBinder_isRemote(self.as_native()) } } /// Try to convert this Binder object into a trait object for the given @@ -116,12 +112,12 @@ impl SpIBinder { /// Return the interface class of this binder object, if associated with /// one. pub fn get_class(&mut self) -> Option<InterfaceClass> { + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. `AIBinder_getClass` returns either a null + // pointer or a valid pointer to an `AIBinder_Class`. After mapping + // null to None, we can safely construct an `InterfaceClass` if the + // pointer was non-null. unsafe { - // Safety: `SpIBinder` guarantees that it always contains a valid - // `AIBinder` pointer. `AIBinder_getClass` returns either a null - // pointer or a valid pointer to an `AIBinder_Class`. After mapping - // null to None, we can safely construct an `InterfaceClass` if the - // pointer was non-null. let class = sys::AIBinder_getClass(self.as_native_mut()); class.as_ref().map(|p| InterfaceClass::from_ptr(p)) } @@ -152,7 +148,8 @@ pub mod unstable_api { /// /// See `SpIBinder::from_raw`. pub unsafe fn new_spibinder(ptr: *mut sys::AIBinder) -> Option<SpIBinder> { - SpIBinder::from_raw(ptr) + // Safety: The caller makes the same guarantees as this requires. + unsafe { SpIBinder::from_raw(ptr) } } } @@ -171,30 +168,24 @@ pub trait AssociateClass { impl AssociateClass for SpIBinder { fn associate_class(&mut self, class: InterfaceClass) -> bool { - unsafe { - // Safety: `SpIBinder` guarantees that it always contains a valid - // `AIBinder` pointer. An `InterfaceClass` can always be converted - // into a valid `AIBinder_Class` pointer, so these parameters are - // always safe. - sys::AIBinder_associateClass(self.as_native_mut(), class.into()) - } + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. An `InterfaceClass` can always be converted + // into a valid `AIBinder_Class` pointer, so these parameters are + // always safe. + unsafe { sys::AIBinder_associateClass(self.as_native_mut(), class.into()) } } } impl Ord for SpIBinder { fn cmp(&self, other: &Self) -> Ordering { - let less_than = unsafe { - // Safety: SpIBinder always holds a valid `AIBinder` pointer, so - // this pointer is always safe to pass to `AIBinder_lt` (null is - // also safe to pass to this function, but we should never do that). - sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) - }; - let greater_than = unsafe { - // Safety: SpIBinder always holds a valid `AIBinder` pointer, so - // this pointer is always safe to pass to `AIBinder_lt` (null is - // also safe to pass to this function, but we should never do that). - sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) - }; + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this + // pointer is always safe to pass to `AIBinder_lt` (null is also safe to + // pass to this function, but we should never do that). + let less_than = unsafe { sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) }; + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this + // pointer is always safe to pass to `AIBinder_lt` (null is also safe to + // pass to this function, but we should never do that). + let greater_than = unsafe { sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) }; if !less_than && !greater_than { Ordering::Equal } else if less_than { @@ -221,10 +212,10 @@ impl Eq for SpIBinder {} impl Clone for SpIBinder { fn clone(&self) -> Self { + // Safety: Cloning a strong reference must increment the reference + // count. We are guaranteed by the `SpIBinder` constructor + // invariants that `self.0` is always a valid `AIBinder` pointer. unsafe { - // Safety: Cloning a strong reference must increment the reference - // count. We are guaranteed by the `SpIBinder` constructor - // invariants that `self.0` is always a valid `AIBinder` pointer. sys::AIBinder_incStrong(self.0.as_ptr()); } Self(self.0) @@ -235,9 +226,9 @@ impl Drop for SpIBinder { // We hold a strong reference to the IBinder in SpIBinder and need to give up // this reference on drop. fn drop(&mut self) { + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we + // know this pointer is safe to pass to `AIBinder_decStrong` here. unsafe { - // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we - // know this pointer is safe to pass to `AIBinder_decStrong` here. sys::AIBinder_decStrong(self.as_native_mut()); } } @@ -246,26 +237,24 @@ impl Drop for SpIBinder { impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { fn prepare_transact(&self) -> Result<Parcel> { let mut input = ptr::null_mut(); + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. It is safe to cast from an + // immutable pointer to a mutable pointer here, because + // `AIBinder_prepareTransaction` only calls immutable `AIBinder` + // methods but the parameter is unfortunately not marked as const. + // + // After the call, input will be either a valid, owned `AParcel` + // pointer, or null. let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. It is safe to cast from an - // immutable pointer to a mutable pointer here, because - // `AIBinder_prepareTransaction` only calls immutable `AIBinder` - // methods but the parameter is unfortunately not marked as const. - // - // After the call, input will be either a valid, owned `AParcel` - // pointer, or null. sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input) }; status_result(status)?; - unsafe { - // Safety: At this point, `input` is either a valid, owned `AParcel` - // pointer, or null. `OwnedParcel::from_raw` safely handles both cases, - // taking ownership of the parcel. - Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) - } + // Safety: At this point, `input` is either a valid, owned `AParcel` + // pointer, or null. `OwnedParcel::from_raw` safely handles both cases, + // taking ownership of the parcel. + unsafe { Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) } } fn submit_transact( @@ -275,23 +264,23 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { flags: TransactionFlags, ) -> Result<Parcel> { let mut reply = ptr::null_mut(); + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. Although `IBinder::transact` is + // not a const method, it is still safe to cast our immutable + // pointer to mutable for the call. First, `IBinder::transact` is + // thread-safe, so concurrency is not an issue. The only way that + // `transact` can affect any visible, mutable state in the current + // process is by calling `onTransact` for a local service. However, + // in order for transactions to be thread-safe, this method must + // dynamically lock its data before modifying it. We enforce this + // property in Rust by requiring `Sync` for remotable objects and + // only providing `on_transact` with an immutable reference to + // `self`. + // + // This call takes ownership of the `data` parcel pointer, and + // passes ownership of the `reply` out parameter to its caller. It + // does not affect ownership of the `binder` parameter. let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. Although `IBinder::transact` is - // not a const method, it is still safe to cast our immutable - // pointer to mutable for the call. First, `IBinder::transact` is - // thread-safe, so concurrency is not an issue. The only way that - // `transact` can affect any visible, mutable state in the current - // process is by calling `onTransact` for a local service. However, - // in order for transactions to be thread-safe, this method must - // dynamically lock its data before modifying it. We enforce this - // property in Rust by requiring `Sync` for remotable objects and - // only providing `on_transact` with an immutable reference to - // `self`. - // - // This call takes ownership of the `data` parcel pointer, and - // passes ownership of the `reply` out parameter to its caller. It - // does not affect ownership of the `binder` parameter. sys::AIBinder_transact( self.as_native() as *mut sys::AIBinder, code, @@ -302,45 +291,45 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { }; status_result(status)?; - unsafe { - // Safety: `reply` is either a valid `AParcel` pointer or null - // after the call to `AIBinder_transact` above, so we can - // construct a `Parcel` out of it. `AIBinder_transact` passes - // ownership of the `reply` parcel to Rust, so we need to - // construct an owned variant. - Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) - } + // Safety: `reply` is either a valid `AParcel` pointer or null + // after the call to `AIBinder_transact` above, so we can + // construct a `Parcel` out of it. `AIBinder_transact` passes + // ownership of the `reply` parcel to Rust, so we need to + // construct an owned variant. + unsafe { Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) } } fn is_binder_alive(&self) -> bool { - unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. - // - // This call does not affect ownership of its pointer parameter. - sys::AIBinder_isAlive(self.as_native()) - } + // Safety: `SpIBinder` guarantees that `self` always contains a valid + // pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. + unsafe { sys::AIBinder_isAlive(self.as_native()) } } #[cfg(not(android_vndk))] fn set_requesting_sid(&mut self, enable: bool) { + // Safety: `SpIBinder` guarantees that `self` always contains a valid + // pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) }; } fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> { let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect(); let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect(); + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the + // file descriptor parameter is always be a valid open file. The + // `args` pointer parameter is a valid pointer to an array of C + // strings that will outlive the call since `args` lives for the + // whole function scope. + // + // This call does not affect ownership of its binder pointer + // parameter and does not take ownership of the file or args array + // parameters. let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the - // file descriptor parameter is always be a valid open file. The - // `args` pointer parameter is a valid pointer to an array of C - // strings that will outlive the call since `args` lives for the - // whole function scope. - // - // This call does not affect ownership of its binder pointer - // parameter and does not take ownership of the file or args array - // parameters. sys::AIBinder_dump( self.as_native_mut(), fp.as_raw_fd(), @@ -353,22 +342,18 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { fn get_extension(&mut self) -> Result<Option<SpIBinder>> { let mut out = ptr::null_mut(); - let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. After this call, the `out` - // parameter will be either null, or a valid pointer to an - // `AIBinder`. - // - // This call passes ownership of the out pointer to its caller - // (assuming it is set to a non-null value). - sys::AIBinder_getExtension(self.as_native_mut(), &mut out) - }; - let ibinder = unsafe { - // Safety: The call above guarantees that `out` is either null or a - // valid, owned pointer to an `AIBinder`, both of which are safe to - // pass to `SpIBinder::from_raw`. - SpIBinder::from_raw(out) - }; + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. After this call, the `out` + // parameter will be either null, or a valid pointer to an + // `AIBinder`. + // + // This call passes ownership of the out pointer to its caller + // (assuming it is set to a non-null value). + let status = unsafe { sys::AIBinder_getExtension(self.as_native_mut(), &mut out) }; + // Safety: The call above guarantees that `out` is either null or a + // valid, owned pointer to an `AIBinder`, both of which are safe to + // pass to `SpIBinder::from_raw`. + let ibinder = unsafe { SpIBinder::from_raw(out) }; status_result(status)?; Ok(ibinder) @@ -377,17 +362,17 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { impl<T: AsNative<sys::AIBinder>> IBinder for T { fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `recipient` can always be + // converted into a valid pointer to an + // `AIBinder_DeathRecipient`. + // + // The cookie is also the correct pointer, and by calling new_cookie, + // we have created a new ref-count to the cookie, which linkToDeath + // takes ownership of. Once the DeathRecipient is unlinked for any + // reason (including if this call fails), the onUnlinked callback + // will consume that ref-count. status_result(unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. `recipient` can always be - // converted into a valid pointer to an - // `AIBinder_DeathRecipient`. - // - // The cookie is also the correct pointer, and by calling new_cookie, - // we have created a new ref-count to the cookie, which linkToDeath - // takes ownership of. Once the DeathRecipient is unlinked for any - // reason (including if this call fails), the onUnlinked callback - // will consume that ref-count. sys::AIBinder_linkToDeath( self.as_native_mut(), recipient.as_native_mut(), @@ -397,13 +382,13 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T { } fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `recipient` can always be + // converted into a valid pointer to an + // `AIBinder_DeathRecipient`. Any value is safe to pass as the + // cookie, although we depend on this value being set by + // `get_cookie` when the death recipient callback is called. status_result(unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. `recipient` can always be - // converted into a valid pointer to an - // `AIBinder_DeathRecipient`. Any value is safe to pass as the - // cookie, although we depend on this value being set by - // `get_cookie` when the death recipient callback is called. sys::AIBinder_unlinkToDeath( self.as_native_mut(), recipient.as_native_mut(), @@ -413,13 +398,11 @@ impl<T: AsNative<sys::AIBinder>> IBinder for T { } fn ping_binder(&mut self) -> Result<()> { - let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. - // - // This call does not affect ownership of its pointer parameter. - sys::AIBinder_ping(self.as_native_mut()) - }; + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. + let status = unsafe { sys::AIBinder_ping(self.as_native_mut()) }; status_result(status) } } @@ -472,35 +455,31 @@ impl fmt::Debug for WpIBinder { } } -/// # Safety -/// -/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe. +/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Send for WpIBinder {} -/// # Safety -/// -/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe. +/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Sync for WpIBinder {} impl WpIBinder { /// Create a new weak reference from an object that can be converted into a /// raw `AIBinder` pointer. fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder { - let ptr = unsafe { - // Safety: `SpIBinder` guarantees that `binder` always contains a - // valid pointer to an `AIBinder`. - sys::AIBinder_Weak_new(binder.as_native_mut()) - }; + // Safety: `SpIBinder` guarantees that `binder` always contains a valid + // pointer to an `AIBinder`. + let ptr = unsafe { sys::AIBinder_Weak_new(binder.as_native_mut()) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new")) } /// Promote this weak reference to a strong reference to the binder object. pub fn promote(&self) -> Option<SpIBinder> { + // Safety: `WpIBinder` always contains a valid weak reference, so we can + // pass this pointer to `AIBinder_Weak_promote`. Returns either null or + // an AIBinder owned by the caller, both of which are valid to pass to + // `SpIBinder::from_raw`. unsafe { - // Safety: `WpIBinder` always contains a valid weak reference, so we - // can pass this pointer to `AIBinder_Weak_promote`. Returns either - // null or an AIBinder owned by the caller, both of which are valid - // to pass to `SpIBinder::from_raw`. let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr()); SpIBinder::from_raw(ptr) } @@ -509,35 +488,27 @@ impl WpIBinder { impl Clone for WpIBinder { fn clone(&self) -> Self { - let ptr = unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, - // so this pointer is always safe to pass to `AIBinder_Weak_clone` - // (although null is also a safe value to pass to this API). - // - // We get ownership of the returned pointer, so can construct a new - // WpIBinder object from it. - sys::AIBinder_Weak_clone(self.0.as_ptr()) - }; + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so + // this pointer is always safe to pass to `AIBinder_Weak_clone` + // (although null is also a safe value to pass to this API). + // + // We get ownership of the returned pointer, so can construct a new + // WpIBinder object from it. + let ptr = unsafe { sys::AIBinder_Weak_clone(self.0.as_ptr()) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone")) } } impl Ord for WpIBinder { fn cmp(&self, other: &Self) -> Ordering { - let less_than = unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, - // so this pointer is always safe to pass to `AIBinder_Weak_lt` - // (null is also safe to pass to this function, but we should never - // do that). - sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) - }; - let greater_than = unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, - // so this pointer is always safe to pass to `AIBinder_Weak_lt` - // (null is also safe to pass to this function, but we should never - // do that). - sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) - }; + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so + // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is + // also safe to pass to this function, but we should never do that). + let less_than = unsafe { sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) }; + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so + // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is + // also safe to pass to this function, but we should never do that). + let greater_than = unsafe { sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) }; if !less_than && !greater_than { Ordering::Equal } else if less_than { @@ -564,9 +535,9 @@ impl Eq for WpIBinder {} impl Drop for WpIBinder { fn drop(&mut self) { + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we + // know this pointer is safe to pass to `AIBinder_Weak_delete` here. unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we - // know this pointer is safe to pass to `AIBinder_Weak_delete` here. sys::AIBinder_Weak_delete(self.0.as_ptr()); } } @@ -574,7 +545,7 @@ impl Drop for WpIBinder { /// Rust wrapper around DeathRecipient objects. /// -/// The cookie in this struct represents an Arc<F> for the owned callback. +/// The cookie in this struct represents an `Arc<F>` for the owned callback. /// This struct owns a ref-count of it, and so does every binder that we /// have been linked with. /// @@ -592,17 +563,13 @@ struct DeathRecipientVtable { cookie_decr_refcount: unsafe extern "C" fn(*mut c_void), } -/// # Safety -/// -/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer -/// to a `Fn` which is `Sync` and `Send` (the cookie field). As +/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and +/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As /// `AIBinder_DeathRecipient` is threadsafe, this structure is too. unsafe impl Send for DeathRecipient {} -/// # Safety -/// -/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer -/// to a `Fn` which is `Sync` and `Send` (the cookie field). As +/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and +/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As /// `AIBinder_DeathRecipient` is threadsafe, this structure is too. unsafe impl Sync for DeathRecipient {} @@ -614,19 +581,17 @@ impl DeathRecipient { F: Fn() + Send + Sync + 'static, { let callback: *const F = Arc::into_raw(Arc::new(callback)); - let recipient = unsafe { - // Safety: The function pointer is a valid death recipient callback. - // - // This call returns an owned `AIBinder_DeathRecipient` pointer - // which must be destroyed via `AIBinder_DeathRecipient_delete` when - // no longer needed. - sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>)) - }; + // Safety: The function pointer is a valid death recipient callback. + // + // This call returns an owned `AIBinder_DeathRecipient` pointer which + // must be destroyed via `AIBinder_DeathRecipient_delete` when no longer + // needed. + let recipient = unsafe { sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>)) }; + // Safety: The function pointer is a valid onUnlinked callback. + // + // All uses of linkToDeath in this file correctly increment the + // ref-count that this onUnlinked callback will decrement. unsafe { - // Safety: The function pointer is a valid onUnlinked callback. - // - // All uses of linkToDeath in this file correctly increment the - // ref-count that this onUnlinked callback will decrement. sys::AIBinder_DeathRecipient_setOnUnlinked( recipient, Some(Self::cookie_decr_refcount::<F>), @@ -648,7 +613,12 @@ impl DeathRecipient { /// /// The caller must handle the returned ref-count correctly. unsafe fn new_cookie(&self) -> *mut c_void { - (self.vtable.cookie_incr_refcount)(self.cookie); + // Safety: `cookie_incr_refcount` points to + // `Self::cookie_incr_refcount`, and `self.cookie` is the cookie for an + // Arc<F>. + unsafe { + (self.vtable.cookie_incr_refcount)(self.cookie); + } // Return a raw pointer with ownership of a ref-count self.cookie @@ -667,13 +637,14 @@ impl DeathRecipient { /// /// # Safety /// - /// The `cookie` parameter must be the cookie for an Arc<F> and + /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// the caller must hold a ref-count to it. unsafe extern "C" fn binder_died<F>(cookie: *mut c_void) where F: Fn() + Send + Sync + 'static, { - let callback = (cookie as *const F).as_ref().unwrap(); + // Safety: The caller promises that `cookie` is for an Arc<F>. + let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; callback(); } @@ -682,34 +653,34 @@ impl DeathRecipient { /// /// # Safety /// - /// The `cookie` parameter must be the cookie for an Arc<F> and + /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// the owner must give up a ref-count to it. unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void) where F: Fn() + Send + Sync + 'static, { - drop(Arc::from_raw(cookie as *const F)); + // Safety: The caller promises that `cookie` is for an Arc<F>. + drop(unsafe { Arc::from_raw(cookie as *const F) }); } /// Callback that increments the ref-count. /// /// # Safety /// - /// The `cookie` parameter must be the cookie for an Arc<F> and + /// The `cookie` parameter must be the cookie for an `Arc<F>` and /// the owner must handle the created ref-count properly. unsafe extern "C" fn cookie_incr_refcount<F>(cookie: *mut c_void) where F: Fn() + Send + Sync + 'static, { - let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F)); + // Safety: The caller promises that `cookie` is for an Arc<F>. + let arc = mem::ManuallyDrop::new(unsafe { Arc::from_raw(cookie as *const F) }); mem::forget(Arc::clone(&arc)); } } -/// # Safety -/// -/// A `DeathRecipient` is always constructed with a valid raw pointer to an -/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this +/// Safety: A `DeathRecipient` is always constructed with a valid raw pointer to +/// an `AIBinder_DeathRecipient`, so it is always type-safe to extract this /// pointer. unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient { fn as_native(&self) -> *const sys::AIBinder_DeathRecipient { @@ -723,18 +694,19 @@ unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient { impl Drop for DeathRecipient { fn drop(&mut self) { + // Safety: `self.recipient` is always a valid, owned + // `AIBinder_DeathRecipient` pointer returned by + // `AIBinder_DeathRecipient_new` when `self` was created. This delete + // method can only be called once when `self` is dropped. unsafe { - // Safety: `self.recipient` is always a valid, owned - // `AIBinder_DeathRecipient` pointer returned by - // `AIBinder_DeathRecipient_new` when `self` was created. This - // delete method can only be called once when `self` is dropped. sys::AIBinder_DeathRecipient_delete(self.recipient); + } - // Safety: We own a ref-count to the cookie, and so does every - // linked binder. This call gives up our ref-count. The linked - // binders should already have given up their ref-count, or should - // do so shortly. - (self.vtable.cookie_decr_refcount)(self.cookie) + // Safety: We own a ref-count to the cookie, and so does every linked + // binder. This call gives up our ref-count. The linked binders should + // already have given up their ref-count, or should do so shortly. + unsafe { + (self.vtable.cookie_decr_refcount)(self.cookie); } } } @@ -754,11 +726,9 @@ pub trait Proxy: Sized + Interface { fn from_binder(binder: SpIBinder) -> Result<Self>; } -/// # Safety -/// -/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow -/// invocation of `IBinder` methods directly from `Interface` objects. It shares -/// the same safety as the implementation for `SpIBinder`. +/// Safety: This is a convenience method that wraps `AsNative` for `SpIBinder` +/// to allow invocation of `IBinder` methods directly from `Interface` objects. +/// It shares the same safety as the implementation for `SpIBinder`. unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T { fn as_native(&self) -> *const sys::AIBinder { self.as_binder().as_native() @@ -773,24 +743,20 @@ unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T { /// exist. pub fn get_service(name: &str) -> Option<SpIBinder> { let name = CString::new(name).ok()?; - unsafe { - // Safety: `AServiceManager_getService` returns either a null pointer or - // a valid pointer to an owned `AIBinder`. Either of these values is - // safe to pass to `SpIBinder::from_raw`. - SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) - } + // Safety: `AServiceManager_getService` returns either a null pointer or a + // valid pointer to an owned `AIBinder`. Either of these values is safe to + // pass to `SpIBinder::from_raw`. + unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) } } /// Retrieve an existing service, or start it if it is configured as a dynamic /// service and isn't yet started. pub fn wait_for_service(name: &str) -> Option<SpIBinder> { let name = CString::new(name).ok()?; - unsafe { - // Safety: `AServiceManager_waitforService` returns either a null - // pointer or a valid pointer to an owned `AIBinder`. Either of these - // values is safe to pass to `SpIBinder::from_raw`. - SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) - } + // Safety: `AServiceManager_waitforService` returns either a null pointer or + // a valid pointer to an owned `AIBinder`. Either of these values is safe to + // pass to `SpIBinder::from_raw`. + unsafe { SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) } } /// Retrieve an existing service for a particular interface, blocking for a few @@ -809,12 +775,10 @@ pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong< pub fn is_declared(interface: &str) -> Result<bool> { let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?; - unsafe { - // Safety: `interface` is a valid null-terminated C-style string and is - // only borrowed for the lifetime of the call. The `interface` local - // outlives this call as it lives for the function scope. - Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) - } + // Safety: `interface` is a valid null-terminated C-style string and is only + // borrowed for the lifetime of the call. The `interface` local outlives + // this call as it lives for the function scope. + unsafe { Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) } } /// Retrieve all declared instances for a particular interface @@ -827,11 +791,13 @@ pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> { // CString, and outlives this callback. The null handling here is just // to avoid the possibility of unwinding across C code if this crate is // ever compiled with panic=unwind. - if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() { + if let Some(instances) = unsafe { opaque.cast::<Vec<CString>>().as_mut() } { // Safety: instance is a valid null-terminated C string with a // lifetime at least as long as this function, and we immediately // copy it into an owned CString. - instances.push(CStr::from_ptr(instance).to_owned()); + unsafe { + instances.push(CStr::from_ptr(instance).to_owned()); + } } else { eprintln!("Opaque pointer was null in get_declared_instances callback!"); } @@ -839,10 +805,10 @@ pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> { let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?; let mut instances: Vec<CString> = vec![]; + // Safety: `interface` and `instances` are borrowed for the length of this + // call and both outlive the call. `interface` is guaranteed to be a valid + // null-terminated C-style string. unsafe { - // Safety: `interface` and `instances` are borrowed for the length of - // this call and both outlive the call. `interface` is guaranteed to be - // a valid null-terminated C-style string. sys::AServiceManager_forEachDeclaredInstance( interface.as_ptr(), &mut instances as *mut _ as *mut c_void, @@ -860,10 +826,8 @@ pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> { }) } -/// # Safety -/// -/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an -/// `AIBinder`, so we can trivially extract this pointer here. +/// Safety: `SpIBinder` guarantees that `binder` always contains a valid pointer +/// to an `AIBinder`, so we can trivially extract this pointer here. unsafe impl AsNative<sys::AIBinder> for SpIBinder { fn as_native(&self) -> *const sys::AIBinder { self.0.as_ptr() diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs index 4886c5fe86..a3a2562eb1 100644 --- a/libs/binder/rust/src/state.rs +++ b/libs/binder/rust/src/state.rs @@ -35,8 +35,8 @@ impl ProcessState { /// not work: the callbacks will be queued but never called as there is no /// thread to call them on. pub fn start_thread_pool() { + // Safety: Safe FFI unsafe { - // Safety: Safe FFI sys::ABinderProcess_startThreadPool(); } } @@ -48,8 +48,8 @@ impl ProcessState { /// called, this is 15. If it is called additional times, the thread pool /// size can only be increased. pub fn set_thread_pool_max_thread_count(num_threads: u32) { + // Safety: Safe FFI unsafe { - // Safety: Safe FFI sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads); } } @@ -62,8 +62,8 @@ impl ProcessState { /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count) /// and [`start_thread_pool`](Self::start_thread_pool). pub fn join_thread_pool() { + // Safety: Safe FFI unsafe { - // Safety: Safe FFI sys::ABinderProcess_joinThreadPool(); } } @@ -86,10 +86,8 @@ impl ThreadState { /// \return calling uid or the current process's UID if this thread isn't /// processing a transaction. pub fn get_calling_uid() -> uid_t { - unsafe { - // Safety: Safe FFI - sys::AIBinder_getCallingUid() - } + // Safety: Safe FFI + unsafe { sys::AIBinder_getCallingUid() } } /// This returns the calling PID assuming that this thread is called from a @@ -111,10 +109,8 @@ impl ThreadState { /// If the transaction being processed is a oneway transaction, then this /// method will return 0. pub fn get_calling_pid() -> pid_t { - unsafe { - // Safety: Safe FFI - sys::AIBinder_getCallingPid() - } + // Safety: Safe FFI + unsafe { sys::AIBinder_getCallingPid() } } /// Determine whether the current thread is currently executing an incoming transaction. @@ -122,10 +118,8 @@ impl ThreadState { /// \return true if the current thread is currently executing an incoming transaction, and false /// otherwise. pub fn is_handling_transaction() -> bool { - unsafe { - // Safety: Safe FFI - sys::AIBinder_isHandlingTransaction() - } + // Safety: Safe FFI + unsafe { sys::AIBinder_isHandlingTransaction() } } /// This function makes the client's security context available to the diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs index 1d1a295221..c5c847b874 100644 --- a/libs/binder/rust/sys/lib.rs +++ b/libs/binder/rust/sys/lib.rs @@ -19,7 +19,20 @@ use std::error::Error; use std::fmt; -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +#[cfg(not(target_os = "trusty"))] +mod bindings { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} + +// Trusty puts the full path to the auto-generated file in BINDGEN_INC_FILE +// and builds it with warnings-as-errors, so we need to use #[allow(bad_style)] +#[cfg(target_os = "trusty")] +#[allow(bad_style)] +mod bindings { + include!(env!("BINDGEN_INC_FILE")); +} + +pub use bindings::*; impl Error for android_c_interface_StatusCode {} diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index ca2cedc19d..c049b807df 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -545,6 +545,11 @@ mod tests { } fn get_expected_selinux_context() -> &'static str { + // SAFETY: The pointer we pass to `getcon` is valid because it comes from a reference, and + // `getcon` doesn't retain it after it returns. If `getcon` succeeds then `out_ptr` will + // point to a valid C string, otherwise it will remain null. We check for null, so the + // pointer we pass to `CStr::from_ptr` must be a valid pointer to a C string. There is a + // memory leak as we don't call `freecon`, but that's fine because this is just a test. unsafe { let mut out_ptr = ptr::null_mut(); assert_eq!(selinux_sys::getcon(&mut out_ptr), 0); diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs index 415ede1a7b..37f182eb08 100644 --- a/libs/binder/rust/tests/ndk_rust_interop.rs +++ b/libs/binder/rust/tests/ndk_rust_interop.rs @@ -28,10 +28,11 @@ use std::os::raw::{c_char, c_int}; /// /// # Safety /// -/// service_name must be a valid, non-null C-style string (null-terminated). +/// service_name must be a valid, non-null C-style string (nul-terminated). #[no_mangle] pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int { - let service_name = CStr::from_ptr(service_name).to_str().unwrap(); + // SAFETY: Our caller promises that service_name is a valid C string. + let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap(); // The Rust class descriptor pointer will not match the NDK one, but the // descriptor strings match so this needs to still associate. @@ -85,10 +86,11 @@ impl IBinderRustNdkInteropTest for Service { /// /// # Safety /// -/// service_name must be a valid, non-null C-style string (null-terminated). +/// service_name must be a valid, non-null C-style string (nul-terminated). #[no_mangle] pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int { - let service_name = CStr::from_ptr(service_name).to_str().unwrap(); + // SAFETY: Our caller promises that service_name is a valid C string. + let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap(); let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default()); match binder::add_service(service_name, service.as_binder()) { Ok(_) => StatusCode::OK as c_int, diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp index ac968237a0..6eb707bcf7 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp @@ -3,19 +3,12 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -rust_fuzz { - name: "parcel_fuzzer_rs", - srcs: [ - "parcel_fuzzer.rs", - ], +rust_defaults { + name: "service_fuzzer_defaults_rs", rustlibs: [ - "libarbitrary", - "libnum_traits", "libbinder_rs", "libbinder_random_parcel_rs", - "binderReadParcelIface-rust", ], - fuzz_config: { cc: [ "waghpawan@google.com", @@ -26,3 +19,18 @@ rust_fuzz { hotlists: ["4637097"], }, } + +rust_fuzz { + name: "parcel_fuzzer_rs", + srcs: [ + "parcel_fuzzer.rs", + ], + defaults: [ + "service_fuzzer_defaults_rs", + ], + rustlibs: [ + "libarbitrary", + "libnum_traits", + "binderReadParcelIface-rust", + ], +} diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs index 29bf92cb97..ce0f742934 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs @@ -105,9 +105,9 @@ fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) { for operation in read_operations { match operation { ReadOperation::SetDataPosition { pos } => { + // Safety: Safe if pos is less than current size of the parcel. + // It relies on C++ code for bound checks unsafe { - // Safety: Safe if pos is less than current size of the parcel. - // It relies on C++ code for bound checks match parcel.set_data_position(pos) { Ok(result) => result, Err(e) => println!("error occurred while setting data position: {:?}", e), diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp index 2537ce0bcb..84130c17e1 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp @@ -19,18 +19,10 @@ rust_fuzz { srcs: [ "service_fuzzer.rs", ], + defaults: [ + "service_fuzzer_defaults_rs", + ], rustlibs: [ - "libbinder_rs", - "libbinder_random_parcel_rs", "testServiceInterface-rust", ], - fuzz_config: { - cc: [ - "waghpawan@google.com", - "smoreland@google.com", - ], - triage_assignee: "waghpawan@google.com", - // hotlist "AIDL fuzzers bugs" on buganizer - hotlists: ["4637097"], - }, } diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs index 1bbd6742f2..896b78f488 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs @@ -35,10 +35,26 @@ pub fn create_random_parcel(fuzzer_data: &[u8]) -> Parcel { /// This API automatically fuzzes provided service pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) { - let ptr = binder.as_native_mut() as *mut c_void; + let mut binders = [binder]; + fuzz_multiple_services(&mut binders, fuzzer_data); +} + +/// This API automatically fuzzes provided services +pub fn fuzz_multiple_services(binders: &mut [&mut SpIBinder], fuzzer_data: &[u8]) { + let mut cppBinders = vec![]; + for binder in binders.iter_mut() { + let ptr = binder.as_native_mut() as *mut c_void; + cppBinders.push(ptr); + } + unsafe { - // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always + // Safety: `Vec::as_mut_ptr` and `slice::as_ptr` always // return valid pointers. - fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len()); + fuzzRustService( + cppBinders.as_mut_ptr(), + cppBinders.len(), + fuzzer_data.as_ptr(), + fuzzer_data.len(), + ); } } diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp index 831bd5660c..cfdd2abd05 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp @@ -21,5 +21,5 @@ extern "C" { void createRandomParcel(void* aParcel, const uint8_t* data, size_t len); // This API is used by fuzzers to automatically fuzz aidl services - void fuzzRustService(void* binder, const uint8_t* data, size_t len); -}
\ No newline at end of file + void fuzzRustService(void** binders, size_t numBinders, const uint8_t* data, size_t len); +} diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs index a2d48b6115..2c8d05facd 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs @@ -89,14 +89,17 @@ pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[ read_parcel_interface!(Option<Vec<u64>>), read_parcel_interface!(Option<Vec<String>>), read_parcel_interface!(ParcelFileDescriptor), + read_parcel_interface!(Vec<ParcelFileDescriptor>), read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>), read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>), read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>), read_parcel_interface!(SpIBinder), + read_parcel_interface!(Vec<SpIBinder>), read_parcel_interface!(Vec<Option<SpIBinder>>), read_parcel_interface!(Option<Vec<SpIBinder>>), read_parcel_interface!(Option<Vec<Option<SpIBinder>>>), read_parcel_interface!(SomeParcelable), + read_parcel_interface!(Vec<SomeParcelable>), read_parcel_interface!(Vec<Option<SomeParcelable>>), read_parcel_interface!(Option<Vec<SomeParcelable>>), read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>), diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs index 6220db4b28..2b6c282530 100644 --- a/libs/binder/rust/tests/serialization.rs +++ b/libs/binder/rust/tests/serialization.rs @@ -26,7 +26,7 @@ use binder::{ use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode}; use std::ffi::{c_void, CStr, CString}; -use std::sync::Once; +use std::sync::OnceLock; #[allow( non_camel_case_types, @@ -70,20 +70,18 @@ macro_rules! assert { }; } -static SERVICE_ONCE: Once = Once::new(); -static mut SERVICE: Option<SpIBinder> = None; +static SERVICE: OnceLock<SpIBinder> = OnceLock::new(); /// Start binder service and return a raw AIBinder pointer to it. /// /// Safe to call multiple times, only creates the service once. #[no_mangle] pub extern "C" fn rust_service() -> *mut c_void { - unsafe { - SERVICE_ONCE.call_once(|| { - SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder()); - }); - SERVICE.as_ref().unwrap().as_raw().cast() - } + let service = SERVICE + .get_or_init(|| BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder()); + // SAFETY: The SpIBinder will remain alive as long as the program is running because it is in + // the static SERVICE, so the pointer is valid forever. + unsafe { service.as_raw().cast() } } /// Empty interface just to use the declare_binder_interface macro @@ -113,11 +111,13 @@ fn on_transact( bindings::Transaction_TEST_BOOL => { assert!(parcel.read::<bool>()?); assert!(!parcel.read::<bool>()?); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL }); assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None); reply.write(&true)?; reply.write(&false)?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_BOOL }[..])?; reply.write(&(None as Option<Vec<bool>>))?; } @@ -125,14 +125,18 @@ fn on_transact( assert_eq!(parcel.read::<i8>()?, 0); assert_eq!(parcel.read::<i8>()?, 1); assert_eq!(parcel.read::<i8>()?, i8::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 }); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<u8>>()?, unsafe { bindings::TESTDATA_U8 }); assert_eq!(parcel.read::<Option<Vec<i8>>>()?, None); reply.write(&0i8)?; reply.write(&1i8)?; reply.write(&i8::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_U8 }[..])?; reply.write(&(None as Option<Vec<i8>>))?; } @@ -140,12 +144,14 @@ fn on_transact( assert_eq!(parcel.read::<u16>()?, 0); assert_eq!(parcel.read::<u16>()?, 1); assert_eq!(parcel.read::<u16>()?, u16::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS }); assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None); reply.write(&0u16)?; reply.write(&1u16)?; reply.write(&u16::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?; reply.write(&(None as Option<Vec<u16>>))?; } @@ -153,12 +159,14 @@ fn on_transact( assert_eq!(parcel.read::<i32>()?, 0); assert_eq!(parcel.read::<i32>()?, 1); assert_eq!(parcel.read::<i32>()?, i32::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 }); assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None); reply.write(&0i32)?; reply.write(&1i32)?; reply.write(&i32::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?; reply.write(&(None as Option<Vec<i32>>))?; } @@ -166,12 +174,14 @@ fn on_transact( assert_eq!(parcel.read::<i64>()?, 0); assert_eq!(parcel.read::<i64>()?, 1); assert_eq!(parcel.read::<i64>()?, i64::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 }); assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None); reply.write(&0i64)?; reply.write(&1i64)?; reply.write(&i64::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?; reply.write(&(None as Option<Vec<i64>>))?; } @@ -179,12 +189,14 @@ fn on_transact( assert_eq!(parcel.read::<u64>()?, 0); assert_eq!(parcel.read::<u64>()?, 1); assert_eq!(parcel.read::<u64>()?, u64::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 }); assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None); reply.write(&0u64)?; reply.write(&1u64)?; reply.write(&u64::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?; reply.write(&(None as Option<Vec<u64>>))?; } @@ -192,10 +204,12 @@ fn on_transact( assert_eq!(parcel.read::<f32>()?, 0f32); let floats = parcel.read::<Vec<f32>>()?; assert!(floats[0].is_nan()); + // SAFETY: Just reading an extern constant. assert_eq!(floats[1..], unsafe { bindings::TESTDATA_FLOAT }[1..]); assert_eq!(parcel.read::<Option<Vec<f32>>>()?, None); reply.write(&0f32)?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_FLOAT }[..])?; reply.write(&(None as Option<Vec<f32>>))?; } @@ -203,10 +217,12 @@ fn on_transact( assert_eq!(parcel.read::<f64>()?, 0f64); let doubles = parcel.read::<Vec<f64>>()?; assert!(doubles[0].is_nan()); + // SAFETY: Just reading an extern constant. assert_eq!(doubles[1..], unsafe { bindings::TESTDATA_DOUBLE }[1..]); assert_eq!(parcel.read::<Option<Vec<f64>>>()?, None); reply.write(&0f64)?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_DOUBLE }[..])?; reply.write(&(None as Option<Vec<f64>>))?; } @@ -216,14 +232,17 @@ fn on_transact( let s: Option<String> = parcel.read()?; assert_eq!(s, None); let s: Option<Vec<Option<String>>> = parcel.read()?; + // SAFETY: Just reading an extern constant. for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) { let expected = + // SAFETY: Just reading an extern constant. unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) }; assert_eq!(s.as_deref(), expected); } let s: Option<Vec<Option<String>>> = parcel.read()?; assert_eq!(s, None); + // SAFETY: Just reading an extern constant. let strings: Vec<Option<String>> = unsafe { bindings::TESTDATA_STRS .iter() @@ -258,8 +277,7 @@ fn on_transact( assert!(ibinders[1].is_none()); assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none()); - let service = - unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() }; + let service = SERVICE.get().expect("Global binder service not initialized").clone(); reply.write(&service)?; reply.write(&(None as Option<&SpIBinder>))?; reply.write(&[Some(&service), None][..])?; diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 41856f9b79..cd3e7c0fef 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -77,6 +77,8 @@ cc_test { static_libs: [ "binderRecordReplayTestIface-cpp", "binderReadParcelIface-cpp", + "libbinder_random_parcel_seeds", + "libbinder_random_parcel", ], test_suites: ["general-tests"], require_root: true, diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl index 2baf68097a..100877847d 100644 --- a/libs/binder/tests/IBinderRpcBenchmark.aidl +++ b/libs/binder/tests/IBinderRpcBenchmark.aidl @@ -18,4 +18,7 @@ interface IBinderRpcBenchmark { @utf8InCpp String repeatString(@utf8InCpp String str); IBinder repeatBinder(IBinder binder); byte[] repeatBytes(in byte[] bytes); + + IBinder gimmeBinder(); + void waitGimmesDestroyed(); } diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp index bc40864020..6712c9cece 100644 --- a/libs/binder/tests/binderAllocationLimits.cpp +++ b/libs/binder/tests/binderAllocationLimits.cpp @@ -216,16 +216,16 @@ TEST(RpcBinderAllocation, SetupRpcServer) { auto server = RpcServer::make(); server->setRootObject(sp<BBinder>::make()); - CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())); + ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str())); std::thread([server]() { server->join(); }).detach(); - status_t status; auto session = RpcSession::make(); - status = session->setupUnixDomainClient(addr.c_str()); - CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str(); + status_t status = session->setupUnixDomainClient(addr.c_str()); + ASSERT_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str(); auto remoteBinder = session->getRootObject(); + ASSERT_NE(remoteBinder, nullptr); size_t mallocs = 0, totalBytes = 0; { @@ -233,7 +233,7 @@ TEST(RpcBinderAllocation, SetupRpcServer) { mallocs++; totalBytes += bytes; }); - CHECK_EQ(OK, remoteBinder->pingBinder()); + ASSERT_EQ(OK, remoteBinder->pingBinder()); } EXPECT_EQ(mallocs, 1); EXPECT_EQ(totalBytes, 40); diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 17d5c8a219..6773c95ed6 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -15,6 +15,7 @@ */ #include <BnBinderRecordReplayTest.h> +#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <binder/Binder.h> @@ -23,6 +24,11 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/RecordedTransaction.h> + +#include <fuzzbinder/libbinder_driver.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <fuzzseeds/random_parcel_seeds.h> + #include <gtest/gtest.h> #include <sys/prctl.h> @@ -30,6 +36,7 @@ #include "parcelables/SingleDataParcelable.h" using namespace android; +using android::generateSeedsFromRecording; using android::binder::Status; using android::binder::debug::RecordedTransaction; using parcelables::SingleDataParcelable; @@ -84,6 +91,44 @@ public: GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>); }; +std::vector<uint8_t> retrieveData(base::borrowed_fd fd) { + struct stat fdStat; + EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1); + EXPECT_TRUE(fdStat.st_size != 0); + + std::vector<uint8_t> buffer(fdStat.st_size); + auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size); + EXPECT_TRUE(readResult != 0); + return std::move(buffer); +} + +void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) { + base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService", + O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666)); + ASSERT_TRUE(seedFd.ok()); + + // generate corpus from this transaction. + generateSeedsFromRecording(seedFd, transaction); + + // Read the data which has been written to seed corpus + ASSERT_EQ(0, lseek(seedFd.get(), 0, SEEK_SET)); + std::vector<uint8_t> seedData = retrieveData(seedFd); + + // use fuzzService to replay the corpus + FuzzedDataProvider provider(seedData.data(), seedData.size()); + fuzzService(binder, std::move(provider)); +} + +void replayBinder(const sp<BpBinder>& binder, const RecordedTransaction& transaction) { + // TODO: move logic to replay RecordedTransaction into RecordedTransaction + Parcel data; + data.setData(transaction.getDataParcel().data(), transaction.getDataParcel().dataSize()); + auto result = binder->transact(transaction.getCode(), data, nullptr, transaction.getFlags()); + + // make sure recording does the thing we expect it to do + EXPECT_EQ(OK, result); +} + class BinderRecordReplayTest : public ::testing::Test { public: void SetUp() override { @@ -98,48 +143,46 @@ public: template <typename T, typename U> void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue, Status (IBinderRecordReplayTest::*get)(U*), U changedValue) { - base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", - O_RDWR | O_CREAT | O_CLOEXEC, 0666)); - ASSERT_TRUE(fd.ok()); - - // record a transaction - mBpBinder->startRecordingBinder(fd); - auto status = (*mInterface.*set)(recordedValue); - EXPECT_TRUE(status.isOk()); - mBpBinder->stopRecordingBinder(); - - // test transaction does the thing we expect it to do - U output; - status = (*mInterface.*get)(&output); - EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, recordedValue); - - // write over the existing state - status = (*mInterface.*set)(changedValue); - EXPECT_TRUE(status.isOk()); - - status = (*mInterface.*get)(&output); - EXPECT_TRUE(status.isOk()); - - EXPECT_EQ(output, changedValue); - - // replay transaction - ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); - std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd); - ASSERT_NE(transaction, std::nullopt); - - // TODO: move logic to replay RecordedTransaction into RecordedTransaction - Parcel data; - data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize()); - auto result = - mBpBinder->transact(transaction->getCode(), data, nullptr, transaction->getFlags()); - - // make sure recording does the thing we expect it to do - EXPECT_EQ(OK, result); - - status = (*mInterface.*get)(&output); - EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, recordedValue); + auto replayFunctions = {&replayBinder, &replayFuzzService}; + for (auto replayFunc : replayFunctions) { + base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", + O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + ASSERT_TRUE(fd.ok()); + + // record a transaction + mBpBinder->startRecordingBinder(fd); + auto status = (*mInterface.*set)(recordedValue); + EXPECT_TRUE(status.isOk()); + mBpBinder->stopRecordingBinder(); + + // test transaction does the thing we expect it to do + U output; + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(output, recordedValue); + + // write over the existing state + status = (*mInterface.*set)(changedValue); + EXPECT_TRUE(status.isOk()); + + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + + EXPECT_EQ(output, changedValue); + + // replay transaction + ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); + std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd); + ASSERT_NE(transaction, std::nullopt); + + const RecordedTransaction& recordedTransaction = *transaction; + // call replay function with recorded transaction + (*replayFunc)(mBpBinder, recordedTransaction); + + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(output, recordedValue); + } } private: diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp index 9c96c4182d..4f10d7417f 100644 --- a/libs/binder/tests/binderRpcBenchmark.cpp +++ b/libs/binder/tests/binderRpcBenchmark.cpp @@ -74,6 +74,44 @@ class MyBinderRpcBenchmark : public BnBinderRpcBenchmark { *out = bytes; return Status::ok(); } + + class CountedBinder : public BBinder { + public: + CountedBinder(const sp<MyBinderRpcBenchmark>& parent) : mParent(parent) { + std::lock_guard<std::mutex> l(mParent->mCountMutex); + mParent->mBinderCount++; + // std::cout << "Count + is now " << mParent->mBinderCount << std::endl; + } + ~CountedBinder() { + { + std::lock_guard<std::mutex> l(mParent->mCountMutex); + mParent->mBinderCount--; + // std::cout << "Count - is now " << mParent->mBinderCount << std::endl; + + // skip notify + if (mParent->mBinderCount != 0) return; + } + mParent->mCountCv.notify_one(); + } + + private: + sp<MyBinderRpcBenchmark> mParent; + }; + + Status gimmeBinder(sp<IBinder>* out) override { + *out = sp<CountedBinder>::make(sp<MyBinderRpcBenchmark>::fromExisting(this)); + return Status::ok(); + } + Status waitGimmesDestroyed() override { + std::unique_lock<std::mutex> l(mCountMutex); + mCountCv.wait(l, [&] { return mBinderCount == 0; }); + return Status::ok(); + } + + friend class CountedBinder; + std::mutex mCountMutex; + std::condition_variable mCountCv; + size_t mBinderCount; }; enum Transport { @@ -212,6 +250,38 @@ BENCHMARK(BM_throughputForTransportAndBytes) ->ArgsProduct({kTransportList, {64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}}); +void BM_collectProxies(benchmark::State& state) { + sp<IBinder> binder = getBinderForOptions(state); + sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder); + CHECK(iface != nullptr); + + const size_t kNumIters = state.range(1); + + while (state.KeepRunning()) { + std::vector<sp<IBinder>> out; + out.resize(kNumIters); + + for (size_t i = 0; i < kNumIters; i++) { + Status ret = iface->gimmeBinder(&out[i]); + CHECK(ret.isOk()) << ret; + } + + out.clear(); + + // we are using a thread up to wait, so make a call to + // force all refcounts to be updated first - current + // binder behavior means we really don't need to wait, + // so code which is waiting is really there to protect + // against any future changes that could delay destruction + android::IInterface::asBinder(iface)->pingBinder(); + + iface->waitGimmesDestroyed(); + } + + SetLabel(state); +} +BENCHMARK(BM_collectProxies)->ArgsProduct({kTransportList, {10, 100, 1000, 5000, 10000, 20000}}); + void BM_repeatBinder(benchmark::State& state) { sp<IBinder> binder = getBinderForOptions(state); CHECK(binder != nullptr); diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index d352ce5bca..4c3c68e2e7 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -249,12 +249,12 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( CHECK_EQ(options.numIncomingConnectionsBySession.size(), options.numSessions); } - SocketType socketType = std::get<0>(GetParam()); - RpcSecurity rpcSecurity = std::get<1>(GetParam()); - uint32_t clientVersion = std::get<2>(GetParam()); - uint32_t serverVersion = std::get<3>(GetParam()); - bool singleThreaded = std::get<4>(GetParam()); - bool noKernel = std::get<5>(GetParam()); + SocketType socketType = GetParam().type; + RpcSecurity rpcSecurity = GetParam().security; + uint32_t clientVersion = GetParam().clientVersion; + uint32_t serverVersion = GetParam().serverVersion; + bool singleThreaded = GetParam().singleThreaded; + bool noKernel = GetParam().noKernel; std::string path = android::base::GetExecutableDirectory(); auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(), @@ -674,7 +674,7 @@ TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) { // session 0 - will check for leaks in destrutor of proc // session 1 - we want to make sure it gets deleted when we drop all references to it auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2}); + {.numThreads = 1, .numSessions = 2, .numIncomingConnectionsBySession = {0, 1}}); wp<RpcSession> session = proc.proc->sessions.at(1).session; @@ -1121,12 +1121,27 @@ TEST_P(BinderRpc, Fds) { } #ifdef BINDER_RPC_TO_TRUSTY_TEST -INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, - ::testing::Combine(::testing::Values(SocketType::TIPC), - ::testing::Values(RpcSecurity::RAW), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(true), ::testing::Values(true)), + +static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() { + std::vector<BinderRpc::ParamType> ret; + + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + ret.push_back(BinderRpc::ParamType{ + .type = SocketType::TIPC, + .security = RpcSecurity::RAW, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + .singleThreaded = true, + .noKernel = true, + }); + } + } + + return ret; +} + +INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()), BinderRpc::PrintParamInfo); #else // BINDER_RPC_TO_TRUSTY_TEST bool testSupportVsockLoopback() { @@ -1246,13 +1261,47 @@ static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) { return ret; } -INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, - ::testing::Combine(::testing::ValuesIn(testSocketTypes()), - ::testing::ValuesIn(RpcSecurityValues()), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(false, true), - ::testing::Values(false, true)), +static std::vector<BinderRpc::ParamType> getBinderRpcParams() { + std::vector<BinderRpc::ParamType> ret; + + constexpr bool full = false; + + for (const auto& type : testSocketTypes()) { + if (full || type == SocketType::UNIX) { + for (const auto& security : RpcSecurityValues()) { + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + for (bool singleThreaded : {false, true}) { + for (bool noKernel : {false, true}) { + ret.push_back(BinderRpc::ParamType{ + .type = type, + .security = security, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + .singleThreaded = singleThreaded, + .noKernel = noKernel, + }); + } + } + } + } + } + } else { + ret.push_back(BinderRpc::ParamType{ + .type = type, + .security = RpcSecurity::RAW, + .clientVersion = RPC_WIRE_PROTOCOL_VERSION, + .serverVersion = RPC_WIRE_PROTOCOL_VERSION, + .singleThreaded = false, + .noKernel = false, + }); + } + } + + return ret; +} + +INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()), BinderRpc::PrintParamInfo); class BinderRpcServerRootObject diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h index 0b8920b5a6..2c9646b30e 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -106,15 +106,23 @@ struct BinderRpcTestProcessSession { } }; -class BinderRpc : public ::testing::TestWithParam< - std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> { +struct BinderRpcParam { + SocketType type; + RpcSecurity security; + uint32_t clientVersion; + uint32_t serverVersion; + bool singleThreaded; + bool noKernel; +}; +class BinderRpc : public ::testing::TestWithParam<BinderRpcParam> { public: - SocketType socketType() const { return std::get<0>(GetParam()); } - RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); } - uint32_t clientVersion() const { return std::get<2>(GetParam()); } - uint32_t serverVersion() const { return std::get<3>(GetParam()); } - bool serverSingleThreaded() const { return std::get<4>(GetParam()); } - bool noKernel() const { return std::get<5>(GetParam()); } + // TODO: avoid unnecessary layer of indirection + SocketType socketType() const { return GetParam().type; } + RpcSecurity rpcSecurity() const { return GetParam().security; } + uint32_t clientVersion() const { return GetParam().clientVersion; } + uint32_t serverVersion() const { return GetParam().serverVersion; } + bool serverSingleThreaded() const { return GetParam().singleThreaded; } + bool noKernel() const { return GetParam().noKernel; } bool clientOrServerSingleThreaded() const { return !kEnableRpcThreads || serverSingleThreaded(); @@ -148,15 +156,16 @@ public: } static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) { - auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param; - auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" + - std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion); - if (singleThreaded) { + auto ret = PrintToString(info.param.type) + "_" + + newFactory(info.param.security)->toCString() + "_clientV" + + std::to_string(info.param.clientVersion) + "_serverV" + + std::to_string(info.param.serverVersion); + if (info.param.singleThreaded) { ret += "_single_threaded"; } else { ret += "_multi_threaded"; } - if (noKernel) { + if (info.param.noKernel) { ret += "_no_kernel"; } else { ret += "_with_kernel"; diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp index 28be10db76..fcb83bdabd 100644 --- a/libs/binder/tests/binderRpcTestTrusty.cpp +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -57,9 +57,9 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( [](size_t n) { return n != 0; }), "Non-zero incoming connections on Trusty"); - RpcSecurity rpcSecurity = std::get<1>(GetParam()); - uint32_t clientVersion = std::get<2>(GetParam()); - uint32_t serverVersion = std::get<3>(GetParam()); + RpcSecurity rpcSecurity = GetParam().security; + uint32_t clientVersion = GetParam().clientVersion; + uint32_t serverVersion = GetParam().serverVersion; auto ret = std::make_unique<TrustyProcessSession>(); @@ -89,12 +89,27 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( return ret; } -INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, - ::testing::Combine(::testing::Values(SocketType::TIPC), - ::testing::Values(RpcSecurity::RAW), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(false), ::testing::Values(true)), +static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() { + std::vector<BinderRpc::ParamType> ret; + + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + ret.push_back(BinderRpc::ParamType{ + .type = SocketType::TIPC, + .security = RpcSecurity::RAW, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + // TODO: should we test both versions here? + .singleThreaded = false, + .noKernel = true, + }); + } + } + + return ret; +} + +INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()), BinderRpc::PrintParamInfo); } // namespace android diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index 1f4601010c..e43508ee79 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -84,7 +84,7 @@ TEST_P(BinderRpc, SeparateRootObject) { GTEST_SKIP() << "This test requires a multi-threaded service"; } - SocketType type = std::get<0>(GetParam()); + SocketType type = GetParam().type; if (type == SocketType::PRECONNECTED || type == SocketType::UNIX || type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) { // we can't get port numbers for unix sockets diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index 35866adf20..383795eff5 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -104,3 +104,43 @@ cc_library_static { local_include_dirs: ["include_random_parcel"], export_include_dirs: ["include_random_parcel"], } + +cc_library { + name: "libbinder_random_parcel_seeds", + host_supported: true, + vendor_available: true, + target: { + darwin: { + enabled: false, + }, + }, + srcs: [ + "random_parcel_seeds.cpp", + ], + shared_libs: [ + "libbase", + "libbinder", + "libbinder_ndk", + "libcutils", + "libutils", + ], + local_include_dirs: [ + "include_random_parcel_seeds", + ], + export_include_dirs: ["include_random_parcel_seeds"], +} + +cc_binary_host { + name: "binder2corpus", + static_libs: [ + "libbinder_random_parcel_seeds", + ], + srcs: [ + "binder2corpus/binder2corpus.cpp", + ], + shared_libs: [ + "libbase", + "libbinder", + "libutils", + ], +} diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md new file mode 100644 index 0000000000..59bf9f31c0 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md @@ -0,0 +1,31 @@ +# binder2corpus + +This tool converts recordings generated by record_binder tool to fuzzer seeds for fuzzService. + +# Steps to add corpus: + +## Start recording the service binder +ex. record_binder start manager + +## Run test on device or keep device idle +ex. atest servicemanager_test + +## Stop the recording +record_binder stop manager + +## Pull the recording on host +Recordings are present on device at /data/local/recordings/<service_name>. Use adb pull. +Use inspect command of record_binder to check if there are some transactions captured. +ex. record_binder inspect manager + +## run corpus generator tool +binder2corpus <recording_path> <dir_to_write_corpus> + +## Build fuzzer and sync data directory +ex. m servicemanager_fuzzer && adb sync data + +## Push corpus on device +ex. adb push servicemanager_fuzzer_corpus/ /data/fuzz/x86_64/servicemanager_fuzzer/ + +## Run fuzzer with corpus directory as argument +ex. adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer_corpus
\ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp new file mode 100644 index 0000000000..c0fdaea0a8 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/unique_fd.h> +#include <binder/RecordedTransaction.h> + +#include <fuzzseeds/random_parcel_seeds.h> + +#include <sys/prctl.h> + +using android::generateSeedsFromRecording; +using android::status_t; +using android::base::unique_fd; +using android::binder::debug::RecordedTransaction; + +status_t generateCorpus(const char* recordingPath, const char* corpusDir) { + unique_fd fd(open(recordingPath, O_RDONLY)); + if (!fd.ok()) { + std::cerr << "Failed to open recording file at path " << recordingPath + << " with error: " << strerror(errno) << '\n'; + return android::BAD_VALUE; + } + + if (auto res = mkdir(corpusDir, 0766); res != 0) { + std::cerr + << "Failed to create corpus directory at path. Delete directory if already exists: " + << corpusDir << std::endl; + return android::BAD_VALUE; + } + + int transactionNumber = 0; + while (auto transaction = RecordedTransaction::fromFile(fd)) { + ++transactionNumber; + std::string filePath = std::string(corpusDir) + std::string("transaction_") + + std::to_string(transactionNumber); + constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC; + android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666)); + if (!corpusFd.ok()) { + std::cerr << "Failed to open fd. Path " << filePath + << " with error: " << strerror(errno) << std::endl; + return android::UNKNOWN_ERROR; + } + generateSeedsFromRecording(corpusFd, transaction.value()); + } + + if (transactionNumber == 0) { + std::cerr << "No valid transaction has been found in recording file: " << recordingPath + << std::endl; + return android::BAD_VALUE; + } + + return android::NO_ERROR; +} + +void printHelp(const char* toolName) { + std::cout << "Usage: \n\n" + << toolName + << " <recording_path> <destination_directory> \n\n*Use " + "record_binder tool for recording binder transactions." + << std::endl; +} + +int main(int argc, char** argv) { + if (argc != 3) { + printHelp(argv[0]); + return 1; + } + const char* sourcePath = argv[1]; + const char* corpusDir = argv[2]; + if (android::NO_ERROR != generateCorpus(sourcePath, corpusDir)) { + std::cerr << "Failed to generate fuzzer corpus." << std::endl; + return 1; + } + return 0; +} diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h new file mode 100644 index 0000000000..5755239c8b --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/file.h> +#include <android-base/hex.h> +#include <android-base/logging.h> + +#include <binder/Binder.h> +#include <binder/Parcel.h> +#include <binder/RecordedTransaction.h> + +#include <private/android_filesystem_config.h> + +#include <vector> + +using android::Parcel; +using android::base::HexString; +using std::vector; + +namespace android { +namespace impl { +// computes the bytes so that if they are passed to FuzzedDataProvider and +// provider.ConsumeIntegralInRange<T>(min, max) is called, it will return val +template <typename T> +void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T min, T max, T val); + +// Calls writeInBuffer method with min and max numeric limits of type T. This method +// is reversal of ConsumeIntegral<T>() in FuzzedDataProvider +template <typename T> +void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val); +} // namespace impl +void generateSeedsFromRecording(base::borrowed_fd fd, + const binder::debug::RecordedTransaction& transaction); +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 45c3a90044..38e6f32cb9 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -21,6 +21,8 @@ #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> +#include <private/android_filesystem_config.h> + namespace android { void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) { @@ -33,6 +35,11 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p .extraFds = {}, }; + // Reserved bytes so that we don't have to change fuzzers and seed corpus if + // we introduce anything new in fuzzService. + std::vector<uint8_t> reservedBytes = provider.ConsumeBytes<uint8_t>(8); + (void)reservedBytes; + // always refresh the calling identity, because we sometimes set it below, but also, // the code we're fuzzing might reset it IPCThreadState::self()->clearCallingIdentity(); @@ -40,7 +47,12 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p // Always take so that a perturbation of just the one ConsumeBool byte will always // take the same path, but with a different UID. Without this, the fuzzer needs to // guess both the change in value and the shift at the same time. - int64_t maybeSetUid = provider.ConsumeIntegral<int64_t>(); + int64_t maybeSetUid = provider.PickValueInArray<int64_t>( + {static_cast<int64_t>(AID_ROOT) << 32, static_cast<int64_t>(AID_SYSTEM) << 32, + provider.ConsumeIntegralInRange<int64_t>(static_cast<int64_t>(AID_ROOT) << 32, + static_cast<int64_t>(AID_USER) << 32), + provider.ConsumeIntegral<int64_t>()}); + if (provider.ConsumeBool()) { // set calling uid IPCThreadState::self()->restoreCallingIdentity(maybeSetUid); @@ -48,8 +60,15 @@ void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& p while (provider.remaining_bytes() > 0) { // Most of the AIDL services will have small set of transaction codes. + // TODO(b/295942369) : Add remaining transact codes from IBinder.h uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral<uint32_t>() - : provider.ConsumeIntegralInRange<uint32_t>(0, 100); + : provider.ConsumeBool() + ? provider.ConsumeIntegralInRange<uint32_t>(0, 100) + : provider.PickValueInArray<uint32_t>( + {IBinder::DUMP_TRANSACTION, IBinder::PING_TRANSACTION, + IBinder::SHELL_COMMAND_TRANSACTION, IBinder::INTERFACE_TRANSACTION, + IBinder::SYSPROPS_TRANSACTION, IBinder::EXTENSION_TRANSACTION, + IBinder::TWEET_TRANSACTION, IBinder::LIKE_TRANSACTION}); uint32_t flags = provider.ConsumeIntegral<uint32_t>(); Parcel data; // for increased fuzz coverage diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp index 0b0ca34586..84b9ff684f 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp @@ -22,6 +22,9 @@ // and APEX users, but we need access to it to fuzz. #include "../../ndk/ibinder_internal.h" +using android::IBinder; +using android::sp; + namespace android { void fuzzService(const std::vector<ndk::SpAIBinder>& binders, FuzzedDataProvider&& provider) { @@ -41,9 +44,14 @@ void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) { extern "C" { // This API is used by fuzzers to automatically fuzz aidl services -void fuzzRustService(void* binder, const uint8_t* data, size_t len) { - AIBinder* aiBinder = static_cast<AIBinder*>(binder); +void fuzzRustService(void** binders, size_t numBinders, const uint8_t* data, size_t len) { + std::vector<sp<IBinder>> cppBinders; + for (size_t binderIndex = 0; binderIndex < numBinders; ++binderIndex) { + AIBinder* aiBinder = static_cast<AIBinder*>(binders[binderIndex]); + cppBinders.push_back(aiBinder->getBinder()); + } + FuzzedDataProvider provider(data, len); - android::fuzzService(aiBinder, std::move(provider)); + android::fuzzService(cppBinders, std::move(provider)); } } // extern "C" diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp index e4dbb2d955..7390d497c4 100644 --- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp @@ -29,40 +29,65 @@ std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { const char* fdType; std::vector<unique_fd> fds = provider->PickValueInArray< - std::function<std::vector<unique_fd>()>>({ - [&]() { - fdType = "ashmem"; - std::vector<unique_fd> ret; - ret.push_back(unique_fd( - ashmem_create_region("binder test region", - provider->ConsumeIntegralInRange<size_t>(0, 4096)))); - return ret; - }, - [&]() { - fdType = "/dev/null"; - std::vector<unique_fd> ret; - ret.push_back(unique_fd(open("/dev/null", O_RDWR))); - return ret; - }, - [&]() { - fdType = "pipefd"; - - int pipefds[2]; - - int flags = O_CLOEXEC; - if (provider->ConsumeBool()) flags |= O_DIRECT; - if (provider->ConsumeBool()) flags |= O_NONBLOCK; - - CHECK_EQ(0, pipe2(pipefds, flags)) << flags; - - if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]); - - std::vector<unique_fd> ret; - ret.push_back(unique_fd(pipefds[0])); - ret.push_back(unique_fd(pipefds[1])); - return ret; - }, - })(); + std::function<std::vector<unique_fd>()>>( + {[&]() { + fdType = "ashmem"; + std::vector<unique_fd> ret; + ret.push_back(unique_fd( + ashmem_create_region("binder test region", + provider->ConsumeIntegralInRange<size_t>(0, 4096)))); + return ret; + }, + [&]() { + fdType = "/dev/null"; + std::vector<unique_fd> ret; + ret.push_back(unique_fd(open("/dev/null", O_RDWR))); + return ret; + }, + [&]() { + fdType = "pipefd"; + + int pipefds[2]; + + int flags = O_CLOEXEC; + if (provider->ConsumeBool()) flags |= O_DIRECT; + if (provider->ConsumeBool()) flags |= O_NONBLOCK; + + CHECK_EQ(0, pipe2(pipefds, flags)) << flags; + + if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]); + + std::vector<unique_fd> ret; + ret.push_back(unique_fd(pipefds[0])); + ret.push_back(unique_fd(pipefds[1])); + return ret; + }, + [&]() { + fdType = "tempfd"; + char name[PATH_MAX]; +#if defined(__ANDROID__) + snprintf(name, sizeof(name), "/data/local/tmp/android-tempfd-test-%d-XXXXXX", + getpid()); +#else + snprintf(name, sizeof(name), "/tmp/android-tempfd-test-%d-XXXXXX", getpid()); +#endif + int fd = mkstemp(name); + CHECK_NE(fd, -1) << "Failed to create file " << name << ", errno: " << errno; + unlink(name); + if (provider->ConsumeBool()) { + CHECK_NE(TEMP_FAILURE_RETRY( + ftruncate(fd, + provider->ConsumeIntegralInRange<size_t>(0, 4096))), + -1) + << "Failed to truncate file, errno: " << errno; + } + + std::vector<unique_fd> ret; + ret.push_back(unique_fd(fd)); + return ret; + } + + })(); for (const auto& fd : fds) CHECK(fd.ok()) << fd.get() << " " << fdType; diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp new file mode 100644 index 0000000000..9e3e2aba77 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/file.h> +#include <android-base/logging.h> + +#include <binder/RecordedTransaction.h> + +#include <fuzzseeds/random_parcel_seeds.h> + +using android::base::WriteFully; + +namespace android { +namespace impl { +template <typename T> +std::vector<uint8_t> reverseBytes(T min, T max, T val) { + uint64_t range = static_cast<uint64_t>(max) - min; + uint64_t result = val - min; + size_t offset = 0; + + std::vector<uint8_t> reverseData; + uint8_t reversed = 0; + reversed |= result; + + while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0) { + reverseData.push_back(reversed); + reversed = 0; + reversed |= (result >> CHAR_BIT); + result = result >> CHAR_BIT; + offset += CHAR_BIT; + } + + return std::move(reverseData); +} + +template <typename T> +void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T min, T max, T val) { + std::vector<uint8_t> reversedData = reverseBytes(min, max, val); + // ConsumeIntegral Calls read buffer from the end. Keep inserting at the front of the buffer + // so that we can align fuzzService operations with seed generation for readability. + integralBuffer.insert(integralBuffer.begin(), reversedData.begin(), reversedData.end()); +} + +template <typename T> +void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) { + // For ConsumeIntegral<T>() calls, FuzzedDataProvider uses numeric limits min and max + // as range + writeReversedBuffer(integralBuffer, std::numeric_limits<T>::min(), + std::numeric_limits<T>::max(), val); +} + +} // namespace impl + +void generateSeedsFromRecording(base::borrowed_fd fd, + const binder::debug::RecordedTransaction& transaction) { + // Write Reserved bytes for future use + std::vector<uint8_t> reservedBytes(8); + CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get(); + + std::vector<uint8_t> integralBuffer; + + // Write UID array : Array elements are initialized in the order that they are declared + // UID array index 2 element + // int64_t aidRoot = 0; + impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32, + static_cast<int64_t>(AID_USER) << 32, + static_cast<int64_t>(AID_ROOT) << 32); + + // UID array index 3 element + impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32); + + // always pick AID_ROOT -> index 0 + size_t uidIndex = 0; + impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(3), + uidIndex); + + // Never set uid in seed corpus + uint8_t writeUid = 0; + impl::writeReversedBuffer(integralBuffer, writeUid); + + // Read random code. this will be from recorded transaction + uint8_t selectCode = 1; + impl::writeReversedBuffer(integralBuffer, selectCode); + + // Get from recorded transaction + uint32_t code = transaction.getCode(); + impl::writeReversedBuffer(integralBuffer, code); + + // Get from recorded transaction + uint32_t flags = transaction.getFlags(); + impl::writeReversedBuffer(integralBuffer, flags); + + // always fuzz primary binder + size_t extraBindersIndex = 0; + impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(0), + extraBindersIndex); + + const Parcel& dataParcel = transaction.getDataParcel(); + + // This buffer holds the bytes which will be used for fillRandomParcel API + std::vector<uint8_t> fillParcelBuffer; + + // Don't take rpc path + uint8_t rpcBranch = 0; + impl::writeReversedBuffer(fillParcelBuffer, rpcBranch); + + // Implicit branch on this path -> options->writeHeader(p, provider) + uint8_t writeHeaderInternal = 0; + impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal); + + // Choose to write data in parcel + size_t fillFuncIndex = 0; + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2), + fillFuncIndex); + + // Write parcel data size from recorded transaction + size_t toWrite = transaction.getDataParcel().dataBufferSize(); + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), toWrite, toWrite); + + // Write parcel data with size towrite from recorded transaction + CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get(); + + // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data + size_t subDataSize = toWrite + fillParcelBuffer.size(); + impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), subDataSize, subDataSize); + + // Write fill parcel buffer + CHECK(WriteFully(fd, fillParcelBuffer.data(), fillParcelBuffer.size())) << fd.get(); + + // Write the integralBuffer to data + CHECK(WriteFully(fd, integralBuffer.data(), integralBuffer.size())) << fd.get(); +} +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp index 7fbf2d0670..d2fa581822 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -20,6 +20,8 @@ #include <binder/IPCThreadState.h> #include <log/log.h> +#include <private/android_filesystem_config.h> + using android::binder::Status; namespace android { @@ -29,6 +31,11 @@ enum class CrashType { ON_PLAIN, ON_BINDER, ON_KNOWN_UID, + ON_SYSTEM_AID, + ON_ROOT_AID, + ON_DUMP_TRANSACT, + ON_SHELL_CMD_TRANSACT, + CRASH_ALWAYS, }; // This service is to verify that fuzzService is functioning properly @@ -48,6 +55,18 @@ public: } break; } + case CrashType::ON_SYSTEM_AID: { + if (IPCThreadState::self()->getCallingUid() == AID_SYSTEM) { + LOG_ALWAYS_FATAL("Expected crash, AID_SYSTEM."); + } + break; + } + case CrashType::ON_ROOT_AID: { + if (IPCThreadState::self()->getCallingUid() == AID_ROOT) { + LOG_ALWAYS_FATAL("Expected crash, AID_ROOT."); + } + break; + } default: break; } @@ -76,6 +95,16 @@ public: return Status::ok(); } + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override { + if (mCrash == CrashType::ON_DUMP_TRANSACT && code == DUMP_TRANSACTION) { + LOG_ALWAYS_FATAL("Expected crash, DUMP."); + } else if (mCrash == CrashType::ON_SHELL_CMD_TRANSACT && + code == SHELL_COMMAND_TRANSACTION) { + LOG_ALWAYS_FATAL("Expected crash, SHELL_CMD."); + } + return BnTestService::onTransact(code, data, reply, flags); + } + private: CrashType mCrash; }; @@ -84,8 +113,10 @@ CrashType gCrashType = CrashType::NONE; extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { if (*argc < 2) { - printf("You must specify at least one argument\n"); - exit(0); // success because this is a crash test + // This fuzzer is also used as test fuzzer to check infra pipeline. + // It should always run and find a crash in TestService. + gCrashType = CrashType::CRASH_ALWAYS; + return 0; } std::string arg = std::string((*argv)[1]); @@ -99,8 +130,16 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { gCrashType = CrashType::ON_PLAIN; } else if (arg == "KNOWN_UID") { gCrashType = CrashType::ON_KNOWN_UID; + } else if (arg == "AID_SYSTEM") { + gCrashType = CrashType::ON_SYSTEM_AID; + } else if (arg == "AID_ROOT") { + gCrashType = CrashType::ON_ROOT_AID; } else if (arg == "BINDER") { gCrashType = CrashType::ON_BINDER; + } else if (arg == "DUMP") { + gCrashType = CrashType::ON_DUMP_TRANSACT; + } else if (arg == "SHELL_CMD") { + gCrashType = CrashType::ON_SHELL_CMD_TRANSACT; } else { printf("INVALID ARG\n"); exit(0); // success because this is a crash test @@ -110,6 +149,9 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (gCrashType == CrashType::CRASH_ALWAYS) { + LOG_ALWAYS_FATAL("Expected crash, This fuzzer will always crash."); + } auto service = sp<TestService>::make(gCrashType); fuzzService(service, FuzzedDataProvider(data, size)); return 0; diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh index e568035af1..5d68fe172e 100755 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -27,10 +27,10 @@ then exit 1 fi -for CRASH_TYPE in PLAIN KNOWN_UID BINDER; do +for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER DUMP SHELL_CMD; do echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE" - ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT" + ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=60 &>"$FUZZER_OUT" echo "INFO: Searching fuzzer output for expected crashes" if grep -q "Expected crash, $CRASH_TYPE." "$FUZZER_OUT" diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp index b8ae84d5c0..dcc8b8ebf7 100644 --- a/libs/binder/tests/rpc_fuzzer/main.cpp +++ b/libs/binder/tests/rpc_fuzzer/main.cpp @@ -135,7 +135,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // b/260736889 - limit arbitrarily, due to thread resource exhaustion, which currently // aborts. Servers should consider RpcServer::setConnectionFilter instead. - constexpr size_t kMaxConnections = 1000; + constexpr size_t kMaxConnections = 10; while (provider.remaining_bytes() > 0) { if (connections.empty() || diff --git a/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp index 09cb2162f7..b80ac53ba2 100644 --- a/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp @@ -16,6 +16,7 @@ #include <commonFuzzHelpers.h> #include <fuzzer/FuzzedDataProvider.h> +#include <functional> #include <string> #include <vector> #include "BufferedTextOutput.h" diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp index 943fb9f285..33a653eb33 100644 --- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFuzz.cpp @@ -54,7 +54,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (transaction.has_value()) { std::FILE* intermediateFile = std::tmpfile(); - android::base::unique_fd fdForWriting(fileno(intermediateFile)); + android::base::unique_fd fdForWriting(dup(fileno(intermediateFile))); auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp new file mode 100644 index 0000000000..2f1f54b0a6 --- /dev/null +++ b/libs/binder/trusty/fuzzer/Android.bp @@ -0,0 +1,39 @@ +// Copyright (C) 2023 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_fuzz { + name: "trusty_binder_fuzzer", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"", + "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"", + "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"", + ], +} + +cc_fuzz { + name: "trusty_binder_rpc_fuzzer", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"", + "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"", + "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"", + ], +} diff --git a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk new file mode 100644 index 0000000000..672d9b75ec --- /dev/null +++ b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk @@ -0,0 +1,38 @@ +# Copyright (C) 2023 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_DIR := $(LOCAL_DIR)/../../.. +LIBBINDER_NDK_BINDGEN_FLAG_FILE := \ + $(LIBBINDER_DIR)/rust/libbinder_ndk_bindgen_flags.txt + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LIBBINDER_DIR)/rust/sys/lib.rs + +MODULE_CRATE_NAME := binder_ndk_sys + +MODULE_LIBRARY_DEPS += \ + $(LIBBINDER_DIR)/trusty \ + $(LIBBINDER_DIR)/trusty/ndk \ + trusty/user/base/lib/trusty-sys \ + +MODULE_BINDGEN_SRC_HEADER := $(LIBBINDER_DIR)/rust/sys/BinderBindings.hpp + +# Add the flags from the flag file +MODULE_BINDGEN_FLAGS += $(shell cat $(LIBBINDER_NDK_BINDGEN_FLAG_FILE)) +MODULE_SRCDEPS += $(LIBBINDER_NDK_BINDGEN_FLAG_FILE) + +include make/library.mk diff --git a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp index f835997187..9df5632e97 100644 --- a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp +++ b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp @@ -20,6 +20,7 @@ #include <fuzzer/FuzzedDataProvider.h> #include <android-base/unique_fd.h> #include <cputimeinstate.h> +#include <functional> using namespace android::bpf; diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp index 96dcce11ea..38233934c8 100644 --- a/libs/fakeservicemanager/Android.bp +++ b/libs/fakeservicemanager/Android.bp @@ -17,6 +17,7 @@ cc_defaults { shared_libs: [ "libbinder", "libutils", + "liblog", ], target: { darwin: { @@ -40,3 +41,41 @@ cc_test_host { static_libs: ["libgmock"], local_include_dirs: ["include"], } + +rust_bindgen { + name: "libfakeservicemanager_bindgen", + crate_name: "fakeservicemanager_bindgen", + host_supported: true, + wrapper_src: "rust/wrappers/FakeServiceManagerWrapper.hpp", + source_stem: "bindings", + visibility: [":__subpackages__"], + bindgen_flags: [ + "--allowlist-function", + "setupFakeServiceManager", + "--allowlist-function", + "clearFakeServiceManager", + ], + shared_libs: [ + "libc++", + "libbinder", + "libfakeservicemanager", + ], +} + +rust_library { + name: "libfakeservicemanager_rs", + crate_name: "fakeservicemanager_rs", + host_supported: true, + srcs: [ + "rust/src/lib.rs", + ], + shared_libs: [ + "libc++", + "libfakeservicemanager", + ], + rustlibs: [ + "libfakeservicemanager_bindgen", + ], + lints: "none", + clippy_lints: "none", +} diff --git a/libs/fakeservicemanager/FakeServiceManager.cpp b/libs/fakeservicemanager/FakeServiceManager.cpp index 3272bbc1aa..ae242f32a3 100644 --- a/libs/fakeservicemanager/FakeServiceManager.cpp +++ b/libs/fakeservicemanager/FakeServiceManager.cpp @@ -16,6 +16,10 @@ #include "fakeservicemanager/FakeServiceManager.h" +using android::sp; +using android::FakeServiceManager; +using android::setDefaultServiceManager; + namespace android { FakeServiceManager::FakeServiceManager() {} @@ -26,6 +30,8 @@ sp<IBinder> FakeServiceManager::getService( const String16& name) const { } sp<IBinder> FakeServiceManager::checkService( const String16& name) const { + std::lock_guard<std::mutex> l(mMutex); + auto it = mNameToService.find(name); if (it == mNameToService.end()) { return nullptr; @@ -36,6 +42,8 @@ sp<IBinder> FakeServiceManager::checkService( const String16& name) const { status_t FakeServiceManager::addService(const String16& name, const sp<IBinder>& service, bool /*allowIsolated*/, int /*dumpsysFlags*/) { + std::lock_guard<std::mutex> l(mMutex); + if (service == nullptr) { return UNEXPECTED_NULL; } @@ -44,6 +52,8 @@ status_t FakeServiceManager::addService(const String16& name, const sp<IBinder>& } Vector<String16> FakeServiceManager::listServices(int /*dumpsysFlags*/) { + std::lock_guard<std::mutex> l(mMutex); + Vector<String16> services; for (auto const& [name, service] : mNameToService) { (void) service; @@ -61,16 +71,20 @@ sp<IBinder> FakeServiceManager::waitForService(const String16& name) { } bool FakeServiceManager::isDeclared(const String16& name) { + std::lock_guard<std::mutex> l(mMutex); + return mNameToService.find(name) != mNameToService.end(); } Vector<String16> FakeServiceManager::getDeclaredInstances(const String16& name) { + std::lock_guard<std::mutex> l(mMutex); + Vector<String16> out; const String16 prefix = name + String16("/"); for (const auto& [registeredName, service] : mNameToService) { (void) service; if (registeredName.startsWith(prefix)) { - out.add(String16(registeredName.string() + prefix.size())); + out.add(String16(registeredName.c_str() + prefix.size())); } } return out; @@ -108,6 +122,29 @@ std::vector<IServiceManager::ServiceDebugInfo> FakeServiceManager::getServiceDeb } void FakeServiceManager::clear() { + std::lock_guard<std::mutex> l(mMutex); + mNameToService.clear(); } } // namespace android + +[[clang::no_destroy]] static sp<FakeServiceManager> gFakeServiceManager; +[[clang::no_destroy]] static std::once_flag gSmOnce; + +extern "C" { + +// Setup FakeServiceManager to mock dependencies in test using this API for rust backend +void setupFakeServiceManager() { + /* Create a FakeServiceManager instance and add required services */ + std::call_once(gSmOnce, [&]() { + gFakeServiceManager = new FakeServiceManager(); + android::setDefaultServiceManager(gFakeServiceManager); + }); +} + +// Clear existing services from Fake SM for rust backend +void clearFakeServiceManager() { + LOG_ALWAYS_FATAL_IF(gFakeServiceManager == nullptr, "Fake Service Manager is not available. Forgot to call setupFakeServiceManager?"); + gFakeServiceManager->clear(); +} +} //extern "C"
\ No newline at end of file diff --git a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h index 97add24ac8..f62241d9c2 100644 --- a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h +++ b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h @@ -19,6 +19,7 @@ #include <binder/IServiceManager.h> #include <map> +#include <mutex> #include <optional> #include <vector> @@ -68,6 +69,7 @@ public: void clear(); private: + mutable std::mutex mMutex; std::map<String16, sp<IBinder>> mNameToService; }; diff --git a/libs/fakeservicemanager/rust/src/lib.rs b/libs/fakeservicemanager/rust/src/lib.rs new file mode 100644 index 0000000000..5b7e756914 --- /dev/null +++ b/libs/fakeservicemanager/rust/src/lib.rs @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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. + */ + +use fakeservicemanager_bindgen::{clearFakeServiceManager, setupFakeServiceManager}; +// Setup FakeServiceManager for testing and fuzzing purposes +pub fn setup_fake_service_manager() { + unsafe { + // Safety: This API creates a new FakeSm object which will be always valid and sets up + // defaultServiceManager + setupFakeServiceManager(); + } +} + +// Setup FakeServiceManager for testing and fuzzing purposes +pub fn clear_fake_service_manager() { + unsafe { + // Safety: This API clears all registered services with Fake SM. This should be only used + // setupFakeServiceManager is already called. + clearFakeServiceManager(); + } +} diff --git a/libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp b/libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp new file mode 100644 index 0000000000..1f5923afba --- /dev/null +++ b/libs/fakeservicemanager/rust/wrappers/FakeServiceManagerWrapper.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2023 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 "fakeservicemanager/FakeServiceManager.h" + +extern "C" { + // Setup FakeServiceManager to mock dependencies in test using this API + void setupFakeServiceManager(); + + // Clear existing services from Fake SM. + void clearFakeServiceManager(); +} // extern "C" diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp index 6fc21c65d1..cb6784c04a 100644 --- a/libs/fakeservicemanager/test_sm.cpp +++ b/libs/fakeservicemanager/test_sm.cpp @@ -22,6 +22,7 @@ #include <binder/IServiceManager.h> #include "fakeservicemanager/FakeServiceManager.h" +#include "rust/wrappers/FakeServiceManagerWrapper.hpp" using android::sp; using android::BBinder; @@ -31,6 +32,7 @@ using android::status_t; using android::FakeServiceManager; using android::String16; using android::IServiceManager; +using android::defaultServiceManager; using testing::ElementsAre; static sp<IBinder> getBinder() { @@ -83,7 +85,7 @@ TEST(GetService, HappyHappy) { EXPECT_EQ(sm->getService(String16("foo")), service); } -TEST(GetService, NonExistant) { +TEST(GetService, NonExistent) { auto sm = new FakeServiceManager(); EXPECT_EQ(sm->getService(String16("foo")), nullptr); @@ -108,7 +110,7 @@ TEST(ListServices, AllServices) { String16("sd"))); } -TEST(WaitForService, NonExistant) { +TEST(WaitForService, NonExistent) { auto sm = new FakeServiceManager(); EXPECT_EQ(sm->waitForService(String16("foo")), nullptr); @@ -124,7 +126,7 @@ TEST(WaitForService, HappyHappy) { EXPECT_EQ(sm->waitForService(String16("foo")), service); } -TEST(IsDeclared, NonExistant) { +TEST(IsDeclared, NonExistent) { auto sm = new FakeServiceManager(); EXPECT_FALSE(sm->isDeclared(String16("foo"))); @@ -139,3 +141,31 @@ TEST(IsDeclared, HappyHappy) { EXPECT_TRUE(sm->isDeclared(String16("foo"))); } + +TEST(SetupFakeServiceManager, NonExistent) { + setupFakeServiceManager(); + + EXPECT_EQ(defaultServiceManager()->getService(String16("foo")), nullptr); +} + +TEST(SetupFakeServiceManager, GetExistingService) { + setupFakeServiceManager(); + sp<IBinder> service = getBinder(); + + EXPECT_EQ(defaultServiceManager()->addService(String16("foo"), service, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); + + EXPECT_EQ(defaultServiceManager()->getService(String16("foo")), service); + clearFakeServiceManager(); +} + +TEST(ClearFakeServiceManager, GetServiceAfterClear) { + setupFakeServiceManager(); + + sp<IBinder> service = getBinder(); + EXPECT_EQ(defaultServiceManager()->addService(String16("foo"), service, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); + + clearFakeServiceManager(); + EXPECT_EQ(defaultServiceManager()->getService(String16("foo")), nullptr); +}
\ No newline at end of file diff --git a/libs/ftl/OWNERS b/libs/ftl/OWNERS new file mode 100644 index 0000000000..3f6129226a --- /dev/null +++ b/libs/ftl/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/native:/services/surfaceflinger/OWNERS
\ No newline at end of file diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 5f5f85a2ad..701a3b2f77 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -60,6 +60,16 @@ typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVe typedef bool (*fpANGLEFreeRulesHandle)(void* handle); typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle); +namespace { +static bool isVndkEnabled() { +#ifdef __BIONIC__ + static bool isVndkEnabled = android::base::GetProperty("ro.vndk.version", "") != ""; + return isVndkEnabled; +#endif + return false; +} +} // namespace + namespace android { enum NativeLibrary { @@ -71,6 +81,8 @@ static constexpr const char* kNativeLibrariesSystemConfigPath[] = {"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt", "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"}; +static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt"; + static std::string vndkVersionStr() { #ifdef __BIONIC__ return base::GetProperty("ro.vndk.version", ""); @@ -108,8 +120,14 @@ static bool readConfig(const std::string& configFile, std::vector<std::string>* } static const std::string getSystemNativeLibraries(NativeLibrary type) { - std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; - insertVndkVersionStr(&nativeLibrariesSystemConfig); + std::string nativeLibrariesSystemConfig = ""; + + if (!isVndkEnabled() && type == NativeLibrary::LLNDK) { + nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath; + } else { + nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; + insertVndkVersionStr(&nativeLibrariesSystemConfig); + } std::vector<std::string> soNames; if (!readConfig(nativeLibrariesSystemConfig, &soNames)) { diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index f50bc203e8..e6331e7282 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -24,11 +24,11 @@ #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> -#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) namespace android { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 7f7a0437f1..db513561fb 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -46,23 +46,23 @@ namespace android { // Macros for include BufferQueueCore information in log messages #define BQ_LOGV(x, ...) \ - ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGD(x, ...) \ - ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGI(x, ...) \ - ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGW(x, ...) \ - ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGE(x, ...) \ - ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) @@ -297,8 +297,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // decrease. mCore->mDequeueCondition.notify_all(); - ATRACE_INT(mCore->mConsumerName.string(), - static_cast<int32_t>(mCore->mQueue.size())); + ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size())); #ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); #endif @@ -717,7 +716,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( status_t BufferQueueConsumer::setConsumerName(const String8& name) { ATRACE_CALL(); - BQ_LOGV("setConsumerName: '%s'", name.string()); + BQ_LOGV("setConsumerName: '%s'", name.c_str()); std::lock_guard<std::mutex> lock(mCore->mMutex); mCore->mConsumerName = name; mConsumerName = name; diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 2930154ad4..648db67fc1 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -41,20 +41,20 @@ namespace android { // Macros for include BufferQueueCore information in log messages -#define BQ_LOGV(x, ...) \ - ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGD(x, ...) \ - ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGI(x, ...) \ - ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGW(x, ...) \ - ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGE(x, ...) \ - ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) static String8 getUniqueName() { @@ -146,23 +146,23 @@ BufferQueueCore::~BufferQueueCore() {} void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const { std::lock_guard<std::mutex> lock(mMutex); - outResult->appendFormat("%s- BufferQueue ", prefix.string()); + outResult->appendFormat("%s- BufferQueue ", prefix.c_str()); outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n", mMaxAcquiredBufferCount, mMaxDequeuedBufferCount); - outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(), + outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.c_str(), mDequeueBufferCannotBlock, mAsyncMode); - outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(), + outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.c_str(), mQueueBufferCanDrop, mLegacyBufferDrop); - outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), + outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.c_str(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.c_str(), mTransformHint, mFrameCounter); - outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.c_str(), mTransformHintInUse, mAutoPrerotation); - outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%sFIFO(%zu):\n", prefix.c_str(), mQueue.size()); - outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string()); + outResult->appendFormat("%s(mConsumerName=%s, ", prefix.c_str(), mConsumerName.c_str()); outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi, mConsumerUsageBits); @@ -173,12 +173,11 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const getProcessName(mConnectedPid, producerProcName); getProcessName(pid, consumerProcName); outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId, - mConnectedPid, producerProcName.string(), pid, - consumerProcName.string()); + mConnectedPid, producerProcName.c_str(), pid, consumerProcName.c_str()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; - outResult->appendFormat("%s %02d:%p ", prefix.string(), current->mSlot, + outResult->appendFormat("%s %02d:%p ", prefix.c_str(), current->mSlot, current->mGraphicBuffer.get()); outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top, current->mCrop.right, current->mCrop.bottom); @@ -187,12 +186,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const ++current; } - outResult->appendFormat("%sSlots:\n", prefix.string()); + outResult->appendFormat("%sSlots:\n", prefix.c_str()); for (int s : mActiveBuffers) { const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer); // A dequeued buffer might be null if it's still being allocated if (buffer.get()) { - outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(), + outResult->appendFormat("%s %s[%02d:%p] ", prefix.c_str(), (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s, buffer.get()); outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(), @@ -200,14 +199,14 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height, buffer->stride, buffer->format); } else { - outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get()); + outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get()); outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n", mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber); } } for (int s : mFreeBuffers) { const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer); - outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get()); + outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get()); outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(), buffer->handle, mSlots[s].mFrameNumber); outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height, @@ -216,7 +215,7 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const for (int s : mFreeSlots) { const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer); - outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(), + outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.c_str(), s, buffer.get(), mSlots[s].mBufferState.string()); } } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index f93468036f..36c2e5891e 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -46,23 +46,23 @@ namespace android { // Macros for include BufferQueueCore information in log messages #define BQ_LOGV(x, ...) \ - ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGD(x, ...) \ - ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGI(x, ...) \ - ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGW(x, ...) \ - ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGE(x, ...) \ - ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) @@ -554,9 +554,9 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou if (returnFlags & BUFFER_NEEDS_REALLOCATION) { BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); - sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( - width, height, format, BQ_LAYER_COUNT, usage, - {mConsumerName.string(), mConsumerName.size()}); + sp<GraphicBuffer> graphicBuffer = + new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage, + {mConsumerName.c_str(), mConsumerName.size()}); status_t error = graphicBuffer->initCheck(); @@ -1018,8 +1018,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; - ATRACE_INT(mCore->mConsumerName.string(), - static_cast<int32_t>(mCore->mQueue.size())); + ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size())); #ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); #endif @@ -1446,7 +1445,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; - allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); + allocName.assign(mCore->mConsumerName.c_str(), mCore->mConsumerName.size()); mCore->mIsAllocating = true; } // Autolock scope @@ -1548,7 +1547,7 @@ status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { String8 BufferQueueProducer::getConsumerName() const { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mCore->mMutex); - BQ_LOGV("getConsumerName: %s", mConsumerName.string()); + BQ_LOGV("getConsumerName: %s", mConsumerName.c_str()); return mConsumerName; } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 9f91d9d3aa..b625c3f75e 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -41,11 +41,11 @@ #include <utils/Trace.h> // Macros for including the ConsumerBase name in log messages -#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) namespace android { @@ -86,8 +86,10 @@ ConsumerBase::~ConsumerBase() { // be done by ConsumerBase::onLastStrongRef(), but it's possible for a // derived class to override that method and not call // ConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); + LOG_ALWAYS_FATAL_IF(!mAbandoned, + "[%s] ~ConsumerBase was called, but the " + "consumer is not abandoned!", + mName.c_str()); } void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { @@ -451,7 +453,7 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, // them to get an accurate timestamp. if (currentStatus == incomingStatus) { char fenceName[32] = {}; - snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot); + snprintf(fenceName, 32, "%.28s:%d", mName.c_str(), slot); sp<Fence> mergedFence = Fence::merge( fenceName, mSlots[slot].mFence, fence); if (!mergedFence.get()) { diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index a62697064b..3031fa11fc 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -23,11 +23,11 @@ #include <gui/BufferItem.h> #include <utils/Log.h> -#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) namespace android { diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index b3647d6126..d49489c5a8 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -52,11 +52,11 @@ namespace android { // Macros for including the GLConsumer name in log messages -#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) static const struct { uint32_t width, height; diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS index 826a418aab..070f6bf532 100644 --- a/libs/gui/OWNERS +++ b/libs/gui/OWNERS @@ -1,3 +1,5 @@ +# Bug component: 1075131 + chrisforbes@google.com jreck@google.com diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 05beb07891..6d44f1079c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1056,7 +1056,7 @@ sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, boo sp<IBinder> display = nullptr; binder::Status status = ComposerServiceAIDL::getComposerService()->createDisplay(std::string( - displayName.string()), + displayName.c_str()), secure, &display); return status.isOk() ? display : nullptr; } diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 8d0828d88e..22c2be7bc7 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -34,13 +34,13 @@ #include <mutex> #include <condition_variable> -#define ATRACE_BUFFER_INDEX(index) \ - do { \ - if (ATRACE_ENABLED()) { \ - char ___traceBuf[1024]; \ - snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \ - android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ - } \ +#define ATRACE_BUFFER_INDEX(index) \ + do { \ + if (ATRACE_ENABLED()) { \ + char ___traceBuf[1024]; \ + snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.c_str(), (index)); \ + android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ + } \ } while (false) namespace android { diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h index 004d87574a..32dc88ba84 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h @@ -298,7 +298,7 @@ struct TWGraphicBufferProducer : public BASE { } Return<void> getConsumerName(HGraphicBufferProducer::getConsumerName_cb _hidl_cb) override { - _hidl_cb(mBase->getConsumerName().string()); + _hidl_cb(mBase->getConsumerName().c_str()); return Void(); } diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index a1405fcb11..449cbf9f75 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -185,31 +185,31 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, while ((err = glGetError()) != GL_NO_ERROR) { msg += String8::format(", %#x", err); } - return ::testing::AssertionFailure(::testing::Message(msg.string())); + return ::testing::AssertionFailure(::testing::Message(msg.c_str())); } if (r >= 0 && abs(r - int(pixel[0])) > tolerance) { msg += String8::format("r(%d isn't %d)", pixel[0], r); } if (g >= 0 && abs(g - int(pixel[1])) > tolerance) { - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += " "; } msg += String8::format("g(%d isn't %d)", pixel[1], g); } if (b >= 0 && abs(b - int(pixel[2])) > tolerance) { - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += " "; } msg += String8::format("b(%d isn't %d)", pixel[2], b); } if (a >= 0 && abs(a - int(pixel[3])) > tolerance) { - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += " "; } msg += String8::format("a(%d isn't %d)", pixel[3], a); } - if (!msg.isEmpty()) { - return ::testing::AssertionFailure(::testing::Message(msg.string())); + if (!msg.empty()) { + return ::testing::AssertionFailure(::testing::Message(msg.c_str())); } else { return ::testing::AssertionSuccess(); } @@ -223,29 +223,29 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, msg += String8::format("left(%d isn't %d)", r1.left, r2.left); } if (abs(r1.top - r2.top) > tolerance) { - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += " "; } msg += String8::format("top(%d isn't %d)", r1.top, r2.top); } if (abs(r1.right - r2.right) > tolerance) { - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += " "; } msg += String8::format("right(%d isn't %d)", r1.right, r2.right); } if (abs(r1.bottom - r2.bottom) > tolerance) { - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += " "; } msg += String8::format("bottom(%d isn't %d)", r1.bottom, r2.bottom); } - if (!msg.isEmpty()) { + if (!msg.empty()) { msg += String8::format(" R1: [%d %d %d %d] R2: [%d %d %d %d]", r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom); - fprintf(stderr, "assertRectEq: %s\n", msg.string()); - return ::testing::AssertionFailure(::testing::Message(msg.string())); + fprintf(stderr, "assertRectEq: %s\n", msg.c_str()); + return ::testing::AssertionFailure(::testing::Message(msg.c_str())); } else { return ::testing::AssertionSuccess(); } diff --git a/libs/gui/tests/OWNERS b/libs/gui/tests/OWNERS new file mode 100644 index 0000000000..48cd30d39d --- /dev/null +++ b/libs/gui/tests/OWNERS @@ -0,0 +1,6 @@ +# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > Surfaces +# Bug component: 316245 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp +# Buganizer template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp + +# Android > Android OS & Apps > graphics > Core Graphics Stack (CoGS) +# Bug component: 1075130 diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp index f34561f668..ccd0e59616 100644 --- a/libs/gui/tests/SurfaceTextureFBO_test.cpp +++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp @@ -59,7 +59,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { glBindFramebuffer(GL_FRAMEBUFFER, 0); for (int i = 0; i < 4; i++) { - SCOPED_TRACE(String8::format("frame %d", i).string()); + SCOPED_TRACE(String8::format("frame %d", i).c_str()); ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index e2b4f3d035..f76c0be265 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -147,8 +147,9 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { for (int i = 0; i < 5; i++) { const android_native_rect_t& crop(crops[i]); - SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", - crop.left, crop.top, crop.right, crop.bottom).string()); + SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left, crop.top, + crop.right, crop.bottom) + .c_str()); ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop)); @@ -308,7 +309,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { mFW->waitForFrame(); for (int i = 0; i < numFrames; i++) { - SCOPED_TRACE(String8::format("frame %d", i).string()); + SCOPED_TRACE(String8::format("frame %d", i).c_str()); // We must wait for each frame to come in because if we ever do an // updateTexImage call that doesn't consume a newly available buffer diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 065cd7a5c7..cb977f04c9 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -408,7 +408,7 @@ TEST_F(SurfaceTest, GetConsumerName) { sp<ANativeWindow> window(surface); native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); - EXPECT_STREQ("TestConsumer", surface->getConsumerName().string()); + EXPECT_STREQ("TestConsumer", surface->getConsumerName().c_str()); } TEST_F(SurfaceTest, GetWideColorSupport) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 2039fa6553..f98de34632 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -209,7 +209,7 @@ status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) { #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status != OK) { ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str()); @@ -363,8 +363,8 @@ char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_ ExactMatch: ; } #if DEBUG_MAPPING - ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", - keyCode, toString(chars, numChars).string(), metaState, result); + ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", keyCode, + toString(chars, numChars).c_str(), metaState, result); #endif return result; } @@ -379,7 +379,7 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t if (!findKey(ch, &keyCode, &metaState)) { #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", - deviceId, toString(chars, numChars).string(), ch); + deviceId, toString(chars, numChars).c_str(), ch); #endif return false; } @@ -391,8 +391,8 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); } #if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", - deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); + ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId, + toString(chars, numChars).c_str(), int32_t(outEvents.size())); for (size_t i = 0; i < outEvents.size(); i++) { ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", outEvents[i].getKeyCode(), outEvents[i].getMetaState(), @@ -849,8 +849,8 @@ KeyCharacterMap::Parser::~Parser() { status_t KeyCharacterMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -872,8 +872,8 @@ status_t KeyCharacterMap::Parser::parse() { status_t status = parseKey(); if (status) return status; } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } break; @@ -889,8 +889,7 @@ status_t KeyCharacterMap::Parser::parse() { mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -900,27 +899,27 @@ status_t KeyCharacterMap::Parser::parse() { if (mState != STATE_TOP) { ALOGE("%s: Unterminated key description at end of file.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (mMap->mType == KeyboardType::UNKNOWN) { ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (mFormat == Format::BASE) { if (mMap->mType == KeyboardType::OVERLAY) { ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } else if (mFormat == Format::OVERLAY) { if (mMap->mType != KeyboardType::OVERLAY) { ALOGE("%s: Overlay keyboard layout missing required keyboard " - "'type OVERLAY' declaration.", - mTokenizer->getLocation().string()); + "'type OVERLAY' declaration.", + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -930,8 +929,7 @@ status_t KeyCharacterMap::Parser::parse() { status_t KeyCharacterMap::Parser::parseType() { if (mMap->mType != KeyboardType::UNKNOWN) { - ALOGE("%s: Duplicate keyboard 'type' declaration.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -953,8 +951,8 @@ status_t KeyCharacterMap::Parser::parseType() { } else if (typeToken == "OVERLAY") { type = KeyboardType::OVERLAY; } else { - ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), - typeToken.string()); + ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(), + typeToken.c_str()); return BAD_VALUE; } @@ -971,8 +969,8 @@ status_t KeyCharacterMap::Parser::parseMap() { mTokenizer->skipDelimiters(WHITESPACE); return parseMapKey(); } - ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } @@ -986,26 +984,26 @@ status_t KeyCharacterMap::Parser::parseMapKey() { } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } KeyedVector<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } @@ -1019,23 +1017,23 @@ status_t KeyCharacterMap::Parser::parseMapKey() { status_t KeyCharacterMap::Parser::parseKey() { String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } if (mMap->mKeys.indexOfKey(keyCode) >= 0) { - ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); if (openBraceToken != "{") { - ALOGE("%s: Expected '{' after key code label, got '%s'.", - mTokenizer->getLocation().string(), openBraceToken.string()); + ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(), + openBraceToken.c_str()); return BAD_VALUE; } @@ -1066,10 +1064,10 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { properties.add(Property(PROPERTY_NUMBER)); } else { int32_t metaState; - status_t status = parseModifier(token.string(), &metaState); + status_t status = parseModifier(token.c_str(), &metaState); if (status) { ALOGE("%s: Expected a property name or modifier, got '%s'.", - mTokenizer->getLocation().string(), token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return status; } properties.add(Property(PROPERTY_META, metaState)); @@ -1087,8 +1085,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } } - ALOGE("%s: Expected ',' or ':' after property name.", - mTokenizer->getLocation().string()); + ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -1106,18 +1103,17 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { char16_t character; status_t status = parseCharacterLiteral(&character); if (status || !character) { - ALOGE("%s: Invalid character literal for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine character literal with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.character = character; @@ -1127,28 +1123,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { if (token == "none") { if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine 'none' with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } haveCharacter = true; } else if (token == "fallback") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str()); if (!keyCode) { ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.fallbackKeyCode = keyCode; @@ -1156,29 +1151,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } else if (token == "replace") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str()); if (!keyCode) { ALOGE("%s: Invalid key code label for replace, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine character literal with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.replacementKeyCode = keyCode; haveReplacement = true; } else { - ALOGE("%s: Expected a key behavior after ':'.", - mTokenizer->getLocation().string()); + ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -1192,8 +1185,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { switch (property.property) { case PROPERTY_LABEL: if (key->label) { - ALOGE("%s: Duplicate label for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } key->label = behavior.character; @@ -1203,8 +1195,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { break; case PROPERTY_NUMBER: if (key->number) { - ALOGE("%s: Duplicate number for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } key->number = behavior.character; @@ -1216,7 +1207,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { for (Behavior* b = key->firstBehavior; b; b = b->next) { if (b->metaState == property.metaState) { ALOGE("%s: Duplicate key behavior for modifier.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -1285,8 +1276,8 @@ status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_ return BAD_VALUE; } if (combinedMeta & metaState) { - ALOGE("%s: Duplicate modifier combination '%s'.", - mTokenizer->getLocation().string(), token.c_str()); + ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(), + token.c_str()); return BAD_VALUE; } @@ -1354,12 +1345,12 @@ status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) } // Ensure that we consumed the entire token. - if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { + if (mTokenizer->nextToken(WHITESPACE).empty()) { return NO_ERROR; } Error: - ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); + ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index 250c0dd9a9..79b6cea292 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -161,7 +161,7 @@ base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::load(Tokenizer* tokeni #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { @@ -289,8 +289,8 @@ KeyLayoutMap::Parser::~Parser() { status_t KeyLayoutMap::Parser::parse() { while (!mTokenizer->isEof()) { - ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); mTokenizer->skipDelimiters(WHITESPACE); @@ -317,16 +317,15 @@ status_t KeyLayoutMap::Parser::parse() { status_t status = parseRequiredKernelConfig(); if (status) return status; } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -346,26 +345,26 @@ status_t KeyLayoutMap::Parser::parseKey() { } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.find(code) != map.end()) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } @@ -375,15 +374,15 @@ status_t KeyLayoutMap::Parser::parseKey() { if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; String8 flagToken = mTokenizer->nextToken(WHITESPACE); - uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string()); + uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.c_str()); if (!flag) { - ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); + ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().c_str(), + flagToken.c_str()); return BAD_VALUE; } if (flags & flag) { - ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); + ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().c_str(), + flagToken.c_str()); return BAD_VALUE; } flags |= flag; @@ -402,15 +401,15 @@ status_t KeyLayoutMap::Parser::parseKey() { status_t KeyLayoutMap::Parser::parseAxis() { String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); char* end; - int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); + int32_t scanCode = int32_t(strtol(scanCodeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); + ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().c_str(), + scanCodeToken.c_str()); return BAD_VALUE; } if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) { - ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); + ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().c_str(), + scanCodeToken.c_str()); return BAD_VALUE; } @@ -423,10 +422,10 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string()); + axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.c_str()); if (axisInfo.axis < 0) { - ALOGE("%s: Expected inverted axis label, got '%s'.", - mTokenizer->getLocation().string(), axisToken.string()); + ALOGE("%s: Expected inverted axis label, got '%s'.", mTokenizer->getLocation().c_str(), + axisToken.c_str()); return BAD_VALUE; } } else if (token == "split") { @@ -434,35 +433,35 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 splitToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); + axisInfo.splitValue = int32_t(strtol(splitToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected split value, got '%s'.", - mTokenizer->getLocation().string(), splitToken.string()); + ALOGE("%s: Expected split value, got '%s'.", mTokenizer->getLocation().c_str(), + splitToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string()); + axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.c_str()); if (axisInfo.axis < 0) { - ALOGE("%s: Expected low axis label, got '%s'.", - mTokenizer->getLocation().string(), lowAxisToken.string()); + ALOGE("%s: Expected low axis label, got '%s'.", mTokenizer->getLocation().c_str(), + lowAxisToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string()); + axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.c_str()); if (axisInfo.highAxis < 0) { - ALOGE("%s: Expected high axis label, got '%s'.", - mTokenizer->getLocation().string(), highAxisToken.string()); + ALOGE("%s: Expected high axis label, got '%s'.", mTokenizer->getLocation().c_str(), + highAxisToken.c_str()); return BAD_VALUE; } } else { - axisInfo.axis = InputEventLookup::getAxisByLabel(token.string()); + axisInfo.axis = InputEventLookup::getAxisByLabel(token.c_str()); if (axisInfo.axis < 0) { ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", - mTokenizer->getLocation().string(), token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } } @@ -476,15 +475,15 @@ status_t KeyLayoutMap::Parser::parseAxis() { if (keywordToken == "flat") { mTokenizer->skipDelimiters(WHITESPACE); String8 flatToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); + axisInfo.flatOverride = int32_t(strtol(flatToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected flat value, got '%s'.", - mTokenizer->getLocation().string(), flatToken.string()); + ALOGE("%s: Expected flat value, got '%s'.", mTokenizer->getLocation().c_str(), + flatToken.c_str()); return BAD_VALUE; } } else { - ALOGE("%s: Expected keyword 'flat', got '%s'.", - mTokenizer->getLocation().string(), keywordToken.string()); + ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } } @@ -507,27 +506,27 @@ status_t KeyLayoutMap::Parser::parseLed() { codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; if (map.find(code) != map.end()) { - ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string()); + int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.c_str()); if (ledCode < 0) { - ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), - ledCodeToken.string()); + ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().c_str(), + ledCodeToken.c_str()); return BAD_VALUE; } @@ -549,7 +548,7 @@ static std::optional<InputDeviceSensorType> getSensorType(const char* token) { } static std::optional<int32_t> getSensorDataIndex(String8 token) { - std::string tokenStr(token.string()); + std::string tokenStr(token.c_str()); if (tokenStr == "X") { return 0; } else if (tokenStr == "Y") { @@ -575,26 +574,26 @@ static std::optional<int32_t> getSensorDataIndex(String8 token) { status_t KeyLayoutMap::Parser::parseSensor() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(), - "abs code", codeToken.string()); + ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().c_str(), + "abs code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map<int32_t, Sensor>& map = mMap->mSensorsByAbsCode; if (map.find(code) != map.end()) { - ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(), - "abs code", codeToken.string()); + ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().c_str(), + "abs code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE); - std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.string()); + std::optional<InputDeviceSensorType> typeOpt = getSensorType(sensorTypeToken.c_str()); if (!typeOpt) { - ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(), - sensorTypeToken.string()); + ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().c_str(), + sensorTypeToken.c_str()); return BAD_VALUE; } InputDeviceSensorType sensorType = typeOpt.value(); @@ -602,8 +601,8 @@ status_t KeyLayoutMap::Parser::parseSensor() { String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE); std::optional<int32_t> indexOpt = getSensorDataIndex(sensorDataIndexToken); if (!indexOpt) { - ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(), - sensorDataIndexToken.string()); + ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().c_str(), + sensorDataIndexToken.c_str()); return BAD_VALUE; } int32_t sensorDataIndex = indexOpt.value(); @@ -624,12 +623,12 @@ status_t KeyLayoutMap::Parser::parseSensor() { // requires_kernel_config CONFIG_HID_PLAYSTATION status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); - std::string configName = codeToken.string(); + std::string configName = codeToken.c_str(); const auto result = mMap->mRequiredKernelConfigs.emplace(configName); if (!result.second) { ALOGE("%s: Duplicate entry for required kernel config %s.", - mTokenizer->getLocation().string(), configName.c_str()); + mTokenizer->getLocation().c_str(), configName.c_str()); return BAD_VALUE; } diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index c3f5151fd1..5f06efaf50 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -55,8 +55,8 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " - "it was not found.", - deviceIdentifier.name.c_str(), keyLayoutName.string()); + "it was not found.", + deviceIdentifier.name.c_str(), keyLayoutName.c_str()); } } @@ -66,8 +66,8 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " - "map '%s' but it was not found.", - deviceIdentifier.name.c_str(), keyCharacterMapName.string()); + "map '%s' but it was not found.", + deviceIdentifier.name.c_str(), keyCharacterMapName.c_str()); } } diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index a842166761..9f72c86a11 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -74,10 +74,10 @@ bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { } char* end; - int value = strtol(stringValue.string(), &end, 10); + int value = strtol(stringValue.c_str(), &end, 10); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; @@ -91,10 +91,10 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { } char* end; - float value = strtof(stringValue.string(), &end); + float value = strtof(stringValue.c_str(), &end); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; @@ -127,7 +127,7 @@ android::base::Result<std::unique_ptr<PropertyMap>> PropertyMap::load(const char #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed property file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status) { @@ -147,16 +147,16 @@ PropertyMap::Parser::~Parser() {} status_t PropertyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); - if (keyToken.isEmpty()) { - ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); + if (keyToken.empty()) { + ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -164,7 +164,7 @@ status_t PropertyMap::Parser::parse() { if (mTokenizer->nextChar() != '=') { ALOGE("%s: Expected '=' between property key and value.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -173,20 +173,20 @@ status_t PropertyMap::Parser::parse() { String8 valueToken = mTokenizer->nextToken(WHITESPACE); if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { ALOGE("%s: Found reserved character '\\' or '\"' in property value.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } if (mMap->hasProperty(keyToken)) { ALOGE("%s: Duplicate property value for key '%s'.", - mTokenizer->getLocation().string(), keyToken.string()); + mTokenizer->getLocation().c_str(), keyToken.c_str()); return BAD_VALUE; } diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp index 865366bcb2..8b8af4290f 100644 --- a/libs/input/VirtualKeyMap.cpp +++ b/libs/input/VirtualKeyMap.cpp @@ -79,8 +79,8 @@ VirtualKeyMap::Parser::~Parser() { status_t VirtualKeyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -91,7 +91,7 @@ status_t VirtualKeyMap::Parser::parse() { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); if (token != "0x01") { ALOGE("%s: Unknown virtual key type, expected 0x01.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -103,7 +103,7 @@ status_t VirtualKeyMap::Parser::parse() { && parseNextIntField(&defn.height); if (!success) { ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -116,9 +116,8 @@ status_t VirtualKeyMap::Parser::parse() { } while (consumeFieldDelimiterAndSkipWhitespace()); if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -146,9 +145,9 @@ bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); char* end; - *outValue = strtol(token.string(), &end, 0); - if (token.isEmpty() || *end != '\0') { - ALOGE("Expected an integer, got '%s'.", token.string()); + *outValue = strtol(token.c_str(), &end, 0); + if (token.empty() || *end != '\0') { + ALOGE("Expected an integer, got '%s'.", token.c_str()); return false; } return true; diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp index 0128859ca6..275b7a4888 100644 --- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp @@ -38,10 +38,10 @@ namespace android { // Macros for including the SurfaceTexture name in log messages -#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) +#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) +#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) +#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) static const struct { uint32_t width, height; diff --git a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp index cf16739e89..32b229d77c 100644 --- a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp @@ -19,7 +19,7 @@ #include <surfacetexture/SurfaceTexture.h> // Macro for including the SurfaceTexture name in log messages -#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) namespace android { diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index d3d4cbafdf..9f610e1a50 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -26,10 +26,10 @@ namespace android { // Macros for including the SurfaceTexture name in log messages -#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) static const mat4 mtxIdentity; diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index 771844f4fe..968c114ed4 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -450,7 +450,7 @@ enum ADataSpace { * * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard */ - ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED + ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED /** * Adobe RGB @@ -471,20 +471,20 @@ enum ADataSpace { ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL /** - * ITU-R Recommendation 601 (BT.601) - 525-line + * ITU-R Recommendation 601 (BT.601) - 625-line * - * Standard-definition television, 525 Lines (NTSC) + * Standard-definition television, 625 Lines (PAL) * - * Use limited range, SMPTE 170M transfer and BT.601_525 standard. + * Use limited range, SMPTE 170M transfer and BT.601_625 standard. */ ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** - * ITU-R Recommendation 709 (BT.709) + * ITU-R Recommendation 601 (BT.601) - 525-line * - * High-definition television + * Standard-definition television, 525 Lines (NTSC) * - * Use limited range, SMPTE 170M transfer and BT.709 standard. + * Use limited range, SMPTE 170M transfer and BT.601_525 standard. */ ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h index e269f0dddf..3f77c78096 100644 --- a/libs/nativewindow/include/android/hardware_buffer_aidl.h +++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h @@ -95,14 +95,22 @@ public: binder_status_t readFromParcel(const AParcel* _Nonnull parcel) { reset(); - return AHardwareBuffer_readFromParcel(parcel, &mBuffer); + if (__builtin_available(android __ANDROID_API_U__, *)) { + return AHardwareBuffer_readFromParcel(parcel, &mBuffer); + } else { + return STATUS_FAILED_TRANSACTION; + } } binder_status_t writeToParcel(AParcel* _Nonnull parcel) const { if (!mBuffer) { return STATUS_BAD_VALUE; } - return AHardwareBuffer_writeToParcel(mBuffer, parcel); + if (__builtin_available(android __ANDROID_API_U__, *)) { + return AHardwareBuffer_writeToParcel(mBuffer, parcel); + } else { + return STATUS_FAILED_TRANSACTION; + } } /** @@ -150,9 +158,13 @@ public: if (!mBuffer) { return "<HardwareBuffer: Invalid>"; } - uint64_t id = 0; - AHardwareBuffer_getId(mBuffer, &id); - return "<HardwareBuffer " + std::to_string(id) + ">"; + if (__builtin_available(android __ANDROID_API_S__, *)) { + uint64_t id = 0; + AHardwareBuffer_getId(mBuffer, &id); + return "<HardwareBuffer " + std::to_string(id) + ">"; + } else { + return "<HardwareBuffer (unknown)>"; + } } private: diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS index 5d23a5ef8d..66e1aa1ca1 100644 --- a/libs/renderengine/OWNERS +++ b/libs/renderengine/OWNERS @@ -1,3 +1,5 @@ +# Bug component: 1075131 + adyabr@google.com alecmouri@google.com djsollen@google.com diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/gl/GLExtensions.cpp index 3dd534e602..b479400a06 100644 --- a/libs/renderengine/gl/GLExtensions.cpp +++ b/libs/renderengine/gl/GLExtensions.cpp @@ -68,19 +68,19 @@ void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* rende } char const* GLExtensions::getVendor() const { - return mVendor.string(); + return mVendor.c_str(); } char const* GLExtensions::getRenderer() const { - return mRenderer.string(); + return mRenderer.c_str(); } char const* GLExtensions::getVersion() const { - return mVersion.string(); + return mVersion.c_str(); } char const* GLExtensions::getExtensions() const { - return mExtensions.string(); + return mExtensions.c_str(); } void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) { @@ -127,11 +127,11 @@ void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExt } char const* GLExtensions::getEGLVersion() const { - return mEGLVersion.string(); + return mEGLVersion.c_str(); } char const* GLExtensions::getEGLExtensions() const { - return mEGLExtensions.string(); + return mEGLExtensions.c_str(); } } // namespace gl diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp index 5ff92402dc..b1bfa3a22e 100644 --- a/libs/renderengine/gl/ProgramCache.cpp +++ b/libs/renderengine/gl/ProgramCache.cpp @@ -62,7 +62,7 @@ public: return out; } friend inline Formatter& operator<<(Formatter& out, const String8& in) { - return operator<<(out, in.string()); + return operator<<(out, in.c_str()); } friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { return (*func)(to); @@ -797,7 +797,7 @@ std::unique_ptr<Program> ProgramCache::generateProgram(const Key& needs) { // fragment shader String8 fs = generateFragmentShader(needs); - return std::make_unique<Program>(needs, vs.string(), fs.string()); + return std::make_unique<Program>(needs, vs.c_str(), fs.c_str()); } void ProgramCache::useProgram(EGLContext context, const Description& description) { diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp index b865c4d5d6..1d61805204 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -74,7 +74,7 @@ Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersi if (hwSensor.maxDelay > INT_MAX) { // Max delay is declared as a 64 bit integer for 64 bit architectures. But it should // always fit in a 32 bit integer, log error and cap it to INT_MAX. - ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.string(), + ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.c_str(), static_cast<int64_t>(hwSensor.maxDelay)); mMaxDelay = INT_MAX; } else { @@ -339,7 +339,7 @@ Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersi if (actualReportingMode != expectedReportingMode) { ALOGE("Reporting Mode incorrect: sensor %s handle=%#010" PRIx32 " type=%" PRId32 " " "actual=%d expected=%d", - mName.string(), mHandle, mType, actualReportingMode, expectedReportingMode); + mName.c_str(), mHandle, mType, actualReportingMode, expectedReportingMode); } } @@ -617,7 +617,7 @@ void Sensor::flattenString8(void*& buffer, size_t& size, const String8& string8) { uint32_t len = static_cast<uint32_t>(string8.length()); FlattenableUtils::write(buffer, size, len); - memcpy(static_cast<char*>(buffer), string8.string(), len); + memcpy(static_cast<char*>(buffer), string8.c_str(), len); FlattenableUtils::advance(buffer, size, len); size -= FlattenableUtils::align<4>(buffer); } @@ -631,7 +631,7 @@ bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& output if (size < len) { return false; } - outputString8.setTo(static_cast<char const*>(buffer), len); + outputString8 = String8(static_cast<char const*>(buffer), len); if (size < FlattenableUtils::align<4>(len)) { ALOGE("Malformed Sensor String8 field. Should be in a 4-byte aligned buffer but is not."); diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 40061cde61..9f814f1c48 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -176,11 +176,8 @@ status_t SensorManager::assertStateLocked() { mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); - if (count == 0) { - ALOGE("Failed to get Sensor list"); - mSensorServer.clear(); - return UNKNOWN_ERROR; - } + // If count is 0, mSensorList will be non-null. This is old + // existing behavior and callers expect this. mSensorList = static_cast<Sensor const**>(malloc(count * sizeof(Sensor*))); LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL"); diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 073da89758..8675f14d43 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -304,6 +304,12 @@ std::string decodePixelFormat(android::PixelFormat format) { return std::string("BGRA_8888"); case android::PIXEL_FORMAT_R_8: return std::string("R_8"); + case android::PIXEL_FORMAT_R_16_UINT: + return std::string("R_16_UINT"); + case android::PIXEL_FORMAT_RG_1616_UINT: + return std::string("RG_1616_UINT"); + case android::PIXEL_FORMAT_RGBA_10101010: + return std::string("RGBA_10101010"); default: return StringPrintf("Unknown %#08x", format); } diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index cc96f83578..4be0a3a9d9 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -115,7 +115,7 @@ sp<Fence> Fence::merge(const char* name, const sp<Fence>& f1, sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1, const sp<Fence>& f2) { - return merge(name.string(), f1, f2); + return merge(name.c_str(), f1, f2); } int Fence::dup() const { diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h index cb61e6a320..494272b1a8 100644 --- a/libs/ui/include/ui/FatVector.h +++ b/libs/ui/include/ui/FatVector.h @@ -65,6 +65,17 @@ public: free(p); } } + + // The STL checks that this member type is present so that + // std::allocator_traits<InlineStdAllocator<T, SIZE>>::rebind_alloc<Other> + // works. std::vector won't be able to construct an + // InlineStdAllocator<Other, SIZE>, because InlineStdAllocator has no + // default constructor, but vector presumably doesn't rebind the allocator + // because it doesn't allocate internal node types. + template <class Other> + struct rebind { + typedef InlineStdAllocator<Other, SIZE> other; + }; Allocation& mAllocation; }; diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 5f441ee84e..4b637dc60b 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -49,6 +49,7 @@ #include "egl_trace.h" using namespace android; +using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; // ---------------------------------------------------------------------------- @@ -406,7 +407,7 @@ EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, EGLint attri // ---------------------------------------------------------------------------- // Translates EGL color spaces to Android data spaces. -static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { +static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace, PixelFormat pixelFormat) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { return HAL_DATASPACE_UNKNOWN; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { @@ -422,7 +423,13 @@ static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) { return HAL_DATASPACE_V0_SCRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) { - return HAL_DATASPACE_BT2020_LINEAR; + if (pixelFormat == PixelFormat::RGBA_FP16) { + return static_cast<android_dataspace>(HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_LINEAR | + HAL_DATASPACE_RANGE_EXTENDED); + } else { + return HAL_DATASPACE_BT2020_LINEAR; + } } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { return HAL_DATASPACE_BT2020_PQ; } @@ -566,8 +573,6 @@ void convertAttribs(const EGLAttrib* attribList, std::vector<EGLint>& newList) { newList.push_back(EGL_NONE); } -using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; - // Gets the native pixel format corrsponding to the passed EGLConfig. void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, PixelFormat* format) { @@ -707,7 +712,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } - android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); + android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace, format); // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN. // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed // at this point. diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 7b9782f4e8..9171534ed6 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -107,7 +107,7 @@ status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<Stri ALOGV("shellCommand"); for (size_t i = 0, n = args.size(); i < n; i++) - ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string()); + ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).c_str()); if (args.size() >= 1) { if (args[0] == String16("vkjson")) return cmdVkjson(out, err); diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp index dd3cc3bd86..141fe021ee 100644 --- a/services/gpuservice/gpumem/GpuMem.cpp +++ b/services/gpuservice/gpumem/GpuMem.cpp @@ -77,7 +77,7 @@ void GpuMem::initialize() { mInitialized.store(true); } -void GpuMem::setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) { +void GpuMem::setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map) { mGpuMemTotalMap = std::move(map); } diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h index 7588b54818..9aa74d6863 100644 --- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h +++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h @@ -44,12 +44,12 @@ private: friend class TestableGpuMem; // set gpu memory total map - void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map); + void setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map); // indicate whether ebpf has been initialized std::atomic<bool> mInitialized = false; // bpf map for GPU memory total data - android::bpf::BpfMap<uint64_t, uint64_t> mGpuMemTotalMap; + android::bpf::BpfMapRO<uint64_t, uint64_t> mGpuMemTotalMap; // gpu memory tracepoint event category static constexpr char kGpuMemTraceGroup[] = "gpu_mem"; diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp index 8dabe4fbdb..1f5b2889d1 100644 --- a/services/gpuservice/tests/unittests/GpuMemTest.cpp +++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp @@ -66,9 +66,7 @@ public: mTestableGpuMem = TestableGpuMem(mGpuMem.get()); mTestableGpuMem.setInitialized(); errno = 0; - mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, - TEST_MAP_SIZE, - BPF_F_NO_PREALLOC)); + mTestMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); EXPECT_EQ(0, errno); EXPECT_TRUE(mTestMap.isValid()); diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp index 5c042102b2..6550df9e58 100644 --- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp +++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp @@ -65,9 +65,7 @@ public: mTestableGpuMem = TestableGpuMem(mGpuMem.get()); errno = 0; - mTestMap = std::move(bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, - TEST_MAP_SIZE, - BPF_F_NO_PREALLOC)); + mTestMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); EXPECT_EQ(0, errno); EXPECT_TRUE(mTestMap.isValid()); diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h index 6c8becb075..f21843fe1a 100644 --- a/services/gpuservice/tests/unittests/TestableGpuMem.h +++ b/services/gpuservice/tests/unittests/TestableGpuMem.h @@ -28,7 +28,7 @@ public: void setInitialized() { mGpuMem->mInitialized.store(true); } - void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) { + void setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map) { mGpuMem->setGpuMemTotalMap(map); } diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index 8300e8a3da..032cb6dea3 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -17,10 +17,11 @@ #ifndef _UI_INPUT_BLOCKING_QUEUE_H #define _UI_INPUT_BLOCKING_QUEUE_H -#include "android-base/thread_annotations.h" #include <condition_variable> +#include <functional> #include <mutex> #include <vector> +#include "android-base/thread_annotations.h" namespace android { diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS index c88bfe97ca..21d208f577 100644 --- a/services/inputflinger/OWNERS +++ b/services/inputflinger/OWNERS @@ -1 +1,2 @@ +# Bug component: 136048 include platform/frameworks/base:/INPUT_OWNERS diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index 2ebdbcfcc4..94c839f761 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -259,14 +259,14 @@ input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* InputDriver::inputGetPropertyKey(input_property_t* property) { if (property != nullptr) { - return property->key.string(); + return property->key.c_str(); } return nullptr; } const char* InputDriver::inputGetPropertyValue(input_property_t* property) { if (property != nullptr) { - return property->value.string(); + return property->value.c_str(); } return nullptr; } @@ -284,7 +284,7 @@ void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) { } void InputDriver::dump(String8& result) { - result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); + result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.c_str()); } } // namespace android diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp index 2da2a70c03..d974c43d78 100644 --- a/services/inputflinger/host/InputFlinger.cpp +++ b/services/inputflinger/host/InputFlinger.cpp @@ -57,7 +57,7 @@ status_t InputFlinger::dump(int fd, const Vector<String16>& args) { } else { dumpInternal(result); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return OK; } diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index f4f3ae95a1..09b20fd8e1 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -251,7 +251,7 @@ void CursorInputMapper::configureParameters() { if (cursorModeString == "navigation") { mParameters.mode = Parameters::Mode::NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str()); } } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index ed3b0eccf0..bc1add59d7 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -429,7 +429,7 @@ void TouchInputMapper::configureParameters() { } else if (gestureModeString == "multi-touch") { mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH; } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); + ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str()); } } @@ -463,7 +463,7 @@ void TouchInputMapper::configureParameters() { } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DeviceType::POINTER; } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str()); } } @@ -484,7 +484,7 @@ void TouchInputMapper::configureParameters() { } else if (orientationString == "ORIENTATION_270") { mParameters.orientation = Parameters::Orientation::ORIENTATION_270; } else if (orientationString != "ORIENTATION_0") { - ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string()); + ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str()); } } @@ -1204,7 +1204,7 @@ void TouchInputMapper::parseCalibration() { } else if (sizeCalibrationString == "area") { out.sizeCalibration = Calibration::SizeCalibration::AREA; } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); + ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str()); } } @@ -1224,7 +1224,7 @@ void TouchInputMapper::parseCalibration() { out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE; } else if (pressureCalibrationString != "default") { ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); + pressureCalibrationString.c_str()); } } @@ -1242,7 +1242,7 @@ void TouchInputMapper::parseCalibration() { out.orientationCalibration = Calibration::OrientationCalibration::VECTOR; } else if (orientationCalibrationString != "default") { ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); + orientationCalibrationString.c_str()); } } @@ -1256,7 +1256,7 @@ void TouchInputMapper::parseCalibration() { out.distanceCalibration = Calibration::DistanceCalibration::SCALED; } else if (distanceCalibrationString != "default") { ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); + distanceCalibrationString.c_str()); } } @@ -1271,7 +1271,7 @@ void TouchInputMapper::parseCalibration() { out.coverageCalibration = Calibration::CoverageCalibration::BOX; } else if (coverageCalibrationString != "default") { ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); + coverageCalibrationString.c_str()); } } } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 03fbf07b16..ad6cf01340 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2784,7 +2784,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe String8 propertyValue; ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) << "Device should have read configuration during configuration phase."; - ASSERT_STREQ("value", propertyValue.string()); + ASSERT_STREQ("value", propertyValue.c_str()); ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled()); diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp index d7ca6e1dbf..47fa8b39ac 100644 --- a/services/sensorservice/RecentEventLogger.cpp +++ b/services/sensorservice/RecentEventLogger.cpp @@ -83,7 +83,7 @@ std::string RecentEventLogger::dump() const { } buffer.append("\n"); } - return std::string(buffer.string()); + return std::string(buffer.c_str()); } /** diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index de050e02d0..184fa7614d 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -299,7 +299,7 @@ std::string SensorDevice::dump() const { result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f); } - return result.string(); + return result.c_str(); } /** diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp index 2dd12e9446..7548742e28 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -63,7 +63,7 @@ void SensorService::SensorDirectConnection::onFirstRef() { void SensorService::SensorDirectConnection::dump(String8& result) const { Mutex::Autolock _l(mConnectionLock); result.appendFormat("\tPackage %s, HAL channel handle %d, total sensor activated %zu\n", - String8(mOpPackageName).string(), getHalChannelHandle(), mActivated.size()); + String8(mOpPackageName).c_str(), getHalChannelHandle(), mActivated.size()); for (auto &i : mActivated) { result.appendFormat("\t\tSensor %#08x, rate %d\n", i.first, i.second); } @@ -79,7 +79,7 @@ void SensorService::SensorDirectConnection::dump(String8& result) const { void SensorService::SensorDirectConnection::dump(ProtoOutputStream* proto) const { using namespace service::SensorDirectConnectionProto; Mutex::Autolock _l(mConnectionLock); - proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).string())); + proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).c_str())); proto->write(HAL_CHANNEL_HANDLE, getHalChannelHandle()); proto->write(NUM_SENSOR_ACTIVATED, int(mActivated.size())); for (auto &i : mActivated) { diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp index f06f9472bd..aa9637719f 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -90,12 +90,12 @@ void SensorService::SensorEventConnection::dump(String8& result) { result.append("NORMAL\n"); } result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | " - "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize, + "max cache size %d\n", mPackageName.c_str(), mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize); for (auto& it : mSensorInfo) { const FlushInfo& flushInfo = it.second; result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n", - mService->getSensorName(it.first).string(), + mService->getSensorName(it.first).c_str(), it.first, flushInfo.mFirstFlushPending ? "First flush pending" : "active", @@ -131,7 +131,7 @@ void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto) } else { proto->write(OPERATING_MODE, OP_MODE_NORMAL); } - proto->write(PACKAGE_NAME, std::string(mPackageName.string())); + proto->write(PACKAGE_NAME, std::string(mPackageName.c_str())); proto->write(WAKE_LOCK_REF_COUNT, int32_t(mWakeLockRefCount)); proto->write(UID, int32_t(mUid)); proto->write(CACHE_SIZE, int32_t(mCacheSize)); @@ -846,7 +846,7 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* if (numBytesRead == sizeof(sensors_event_t)) { if (!mDataInjectionMode) { ALOGE("Data injected in normal mode, dropping event" - "package=%s uid=%d", mPackageName.string(), mUid); + "package=%s uid=%d", mPackageName.c_str(), mUid); // Unregister call backs. return 0; } diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp index e27b52b23e..5c00260008 100644 --- a/services/sensorservice/SensorFusion.cpp +++ b/services/sensorservice/SensorFusion.cpp @@ -19,6 +19,7 @@ #include "SensorService.h" #include <android/util/ProtoOutputStream.h> +#include <cutils/properties.h> #include <frameworks/base/core/proto/android/service/sensor_service.proto.h> namespace android { @@ -60,10 +61,12 @@ SensorFusion::SensorFusion() mGyro = uncalibratedGyro; } - // 200 Hz for gyro events is a good compromise between precision - // and power/cpu usage. - mEstimatedGyroRate = 200; - mTargetDelayNs = 1000000000LL/mEstimatedGyroRate; + // Wearable devices will want to tune this parameter + // to 100 (Hz) in device.mk to save some power. + int32_t value = property_get_int32( + "sensors.aosp_low_power_sensor_fusion.maximum_rate", 200); + mEstimatedGyroRate = static_cast<float>(value); + mTargetDelayNs = 1000000000LL / mEstimatedGyroRate; for (int i = 0; i<NUM_FUSION_MODE; ++i) { mFusions[i].init(i); diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp index 85ce0f0018..02f22c5c4a 100644 --- a/services/sensorservice/SensorList.cpp +++ b/services/sensorservice/SensorList.cpp @@ -134,12 +134,12 @@ std::string SensorList::dump() const { "%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32 ") | perm: %s | flags: 0x%08x\n", s.getHandle(), - s.getName().string(), - s.getVendor().string(), + s.getName().c_str(), + s.getVendor().c_str(), s.getVersion(), - s.getStringType().string(), + s.getStringType().c_str(), s.getType(), - s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a", + s.getRequiredPermission().size() ? s.getRequiredPermission().c_str() : "n/a", static_cast<int>(s.getFlags())); result.append("\t"); @@ -208,7 +208,7 @@ std::string SensorList::dump() const { } return true; }); - return std::string(result.string()); + return std::string(result.c_str()); } /** @@ -225,13 +225,13 @@ void SensorList::dump(util::ProtoOutputStream* proto) const { forEachSensor([&proto] (const Sensor& s) -> bool { const uint64_t token = proto->start(SENSORS); proto->write(HANDLE, s.getHandle()); - proto->write(NAME, std::string(s.getName().string())); - proto->write(VENDOR, std::string(s.getVendor().string())); + proto->write(NAME, std::string(s.getName().c_str())); + proto->write(VENDOR, std::string(s.getVendor().c_str())); proto->write(VERSION, s.getVersion()); - proto->write(STRING_TYPE, std::string(s.getStringType().string())); + proto->write(STRING_TYPE, std::string(s.getStringType().c_str())); proto->write(TYPE, s.getType()); proto->write(REQUIRED_PERMISSION, std::string(s.getRequiredPermission().size() ? - s.getRequiredPermission().string() : "")); + s.getRequiredPermission().c_str() : "")); proto->write(FLAGS, int(s.getFlags())); switch (s.getReportingMode()) { case AREPORTING_MODE_CONTINUOUS: diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h index a34a65bbdd..dc9e8215e7 100644 --- a/services/sensorservice/SensorRegistrationInfo.h +++ b/services/sensorservice/SensorRegistrationInfo.h @@ -93,7 +93,7 @@ public: using namespace service::SensorRegistrationInfoProto; proto->write(TIMESTAMP_SEC, int64_t(mRealtimeSec)); proto->write(SENSOR_HANDLE, mSensorHandle); - proto->write(PACKAGE_NAME, std::string(mPackageName.string())); + proto->write(PACKAGE_NAME, std::string(mPackageName.c_str())); proto->write(PID, int32_t(mPid)); proto->write(UID, int32_t(mUid)); proto->write(SAMPLING_RATE_US, mSamplingRateUs); diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index e0a4f034cb..3d613596f5 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -472,7 +472,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { mCurrentOperatingMode = RESTRICTED; // temporarily stop all sensor direct report and disable sensors disableAllSensorsLocked(&connLock); - mWhiteListedPackage.setTo(String8(args[1])); + mWhiteListedPackage = String8(args[1]); return status_t(NO_ERROR); } else if (args.size() == 1 && args[0] == String16("enable")) { // If currently in restricted mode, reset back to NORMAL mode else ignore. @@ -496,7 +496,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { // Re-enable sensors. dev.enableAllSensors(); } - mWhiteListedPackage.setTo(String8(args[1])); + mWhiteListedPackage = String8(args[1]); return NO_ERROR; } else if (mCurrentOperatingMode == DATA_INJECTION) { // Already in DATA_INJECTION mode. Treat this as a no_op. @@ -531,13 +531,13 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { for (auto&& i : mRecentEvent) { sp<SensorInterface> s = mSensors.getInterface(i.first); if (!i.second->isEmpty()) { - if (privileged || s->getSensor().getRequiredPermission().isEmpty()) { + if (privileged || s->getSensor().getRequiredPermission().empty()) { i.second->setFormat("normal"); } else { i.second->setFormat("mask_data"); } // if there is events and sensor does not need special permission. - result.appendFormat("%s: ", s->getSensor().getName().string()); + result.appendFormat("%s: ", s->getSensor().getName().c_str()); result.append(i.second->dump().c_str()); } } @@ -548,7 +548,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { int handle = mActiveSensors.keyAt(i); if (dev.isSensorActive(handle)) { result.appendFormat("%s (handle=0x%08x, connections=%zu)\n", - getSensorName(handle).string(), + getSensorName(handle).c_str(), handle, mActiveSensors.valueAt(i)->getNumConnections()); } @@ -564,10 +564,10 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { result.appendFormat(" NORMAL\n"); break; case RESTRICTED: - result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string()); + result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.c_str()); break; case DATA_INJECTION: - result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string()); + result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.c_str()); } result.appendFormat("Sensor Privacy: %s\n", mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled"); @@ -605,7 +605,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { } while(startIndex != currentIndex); } } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return NO_ERROR; } @@ -649,11 +649,11 @@ status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock for (auto&& i : mRecentEvent) { sp<SensorInterface> s = mSensors.getInterface(i.first); if (!i.second->isEmpty()) { - i.second->setFormat(privileged || s->getSensor().getRequiredPermission().isEmpty() ? + i.second->setFormat(privileged || s->getSensor().getRequiredPermission().empty() ? "normal" : "mask_data"); const uint64_t mToken = proto.start(service::SensorEventsProto::RECENT_EVENTS_LOGS); proto.write(service::SensorEventsProto::RecentEventsLog::NAME, - std::string(s->getSensor().getName().string())); + std::string(s->getSensor().getName().c_str())); i.second->dump(&proto); proto.end(mToken); } @@ -667,7 +667,7 @@ status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock if (dev.isSensorActive(handle)) { token = proto.start(ACTIVE_SENSORS); proto.write(service::ActiveSensorProto::NAME, - std::string(getSensorName(handle).string())); + std::string(getSensorName(handle).c_str())); proto.write(service::ActiveSensorProto::HANDLE, handle); proto.write(service::ActiveSensorProto::NUM_CONNECTIONS, int(mActiveSensors.valueAt(i)->getNumConnections())); @@ -685,11 +685,11 @@ status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock break; case RESTRICTED: proto.write(OPERATING_MODE, OP_MODE_RESTRICTED); - proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string())); + proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.c_str())); break; case DATA_INJECTION: proto.write(OPERATING_MODE, OP_MODE_DATA_INJECTION); - proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string())); + proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.c_str())); break; default: proto.write(OPERATING_MODE, OP_MODE_UNKNOWN); @@ -832,8 +832,8 @@ static status_t getUidForPackage(String16 packageName, int userId, /*inout*/uid_ PermissionController pc; uid = pc.getPackageUid(packageName, 0); if (uid <= 0) { - ALOGE("Unknown package: '%s'", String8(packageName).string()); - dprintf(err, "Unknown package: '%s'\n", String8(packageName).string()); + ALOGE("Unknown package: '%s'", String8(packageName).c_str()); + dprintf(err, "Unknown package: '%s'\n", String8(packageName).c_str()); return BAD_VALUE; } @@ -858,7 +858,7 @@ status_t SensorService::handleSetUidState(Vector<String16>& args, int err) { if (args[2] == String16("active")) { active = true; } else if ((args[2] != String16("idle"))) { - ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string()); + ALOGE("Expected active or idle but got: '%s'", String8(args[2]).c_str()); return BAD_VALUE; } @@ -1351,8 +1351,8 @@ Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName accessibleSensorList.add(sensor); } else if (sensor.getType() != SENSOR_TYPE_HEAD_TRACKER) { ALOGI("Skipped sensor %s because it requires permission %s and app op %" PRId32, - sensor.getName().string(), - sensor.getRequiredPermission().string(), + sensor.getName().c_str(), + sensor.getRequiredPermission().c_str(), sensor.getRequiredAppOp()); } } @@ -1996,10 +1996,10 @@ bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation, !isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) { if (!mHtRestricted) { ALOGI("Permitting access to HT sensor type outside system (%s)", - String8(opPackageName).string()); + String8(opPackageName).c_str()); } else { - ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).string(), - operation, sensor.getName().string()); + ALOGW("%s %s a sensor (%s) as a non-system client", String8(opPackageName).c_str(), + operation, sensor.getName().c_str()); return false; } } @@ -2032,8 +2032,8 @@ bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation, } if (!canAccess) { - ALOGE("%s %s a sensor (%s) without holding %s", String8(opPackageName).string(), - operation, sensor.getName().string(), sensor.getRequiredPermission().string()); + ALOGE("%s %s a sensor (%s) without holding %s", String8(opPackageName).c_str(), + operation, sensor.getName().c_str(), sensor.getRequiredPermission().c_str()); } return canAccess; @@ -2124,7 +2124,7 @@ void SensorService::sendEventsFromCache(const sp<SensorEventConnection>& connect } bool SensorService::isWhiteListedPackage(const String8& packageName) { - return (packageName.contains(mWhiteListedPackage.string())); + return (packageName.contains(mWhiteListedPackage.c_str())); } bool SensorService::isOperationRestrictedLocked(const String16& opPackageName) { diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp index 9b0334443b..ee4c5f819c 100644 --- a/services/sensorservice/aidl/SensorManager.cpp +++ b/services/sensorservice/aidl/SensorManager.cpp @@ -197,6 +197,11 @@ ndk::ScopedAStatus SensorManagerAidl::getSensorList(std::vector<SensorInfo>* _ai sp<Looper> SensorManagerAidl::getLooper() { std::lock_guard<std::mutex> lock(mThreadMutex); + if (!mJavaVm) { + LOG(ERROR) << "No Java VM. This must be running in a test or fuzzer."; + return mLooper; + } + if (!mPollThread.joinable()) { // if thread not initialized, start thread mStopThread = false; diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp index 5fa594d01d..d338d02675 100644 --- a/services/sensorservice/hidl/utils.cpp +++ b/services/sensorservice/hidl/utils.cpp @@ -32,8 +32,8 @@ SensorInfo convertSensor(const Sensor& src) { SensorInfo dst; const String8& name = src.getName(); const String8& vendor = src.getVendor(); - dst.name = hidl_string{name.string(), name.size()}; - dst.vendor = hidl_string{vendor.string(), vendor.size()}; + dst.name = hidl_string{name.c_str(), name.size()}; + dst.vendor = hidl_string{vendor.c_str(), vendor.size()}; dst.version = src.getVersion(); dst.sensorHandle = src.getHandle(); dst.type = static_cast<::android::hardware::sensors::V1_0::SensorType>( diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp index caf7f03361..8b4b3f61b0 100644 --- a/services/sensorservice/tests/sensorservicetest.cpp +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -105,7 +105,7 @@ int main() { Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER); printf("accelerometer=%p (%s)\n", - accelerometer, accelerometer->getName().string()); + accelerometer, accelerometer->getName().c_str()); sStartTime = systemTime(); @@ -130,7 +130,7 @@ int main() { printf("ALOOPER_POLL_TIMEOUT\n"); break; case ALOOPER_POLL_ERROR: - printf("ALOOPER_POLL_TIMEOUT\n"); + printf("ALOOPER_POLL_ERROR\n"); break; default: printf("ugh? poll returned %d\n", ret); diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 7361a4fdef..a1035f01bf 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -49,11 +49,11 @@ namespace android { // Macros for including the BufferLayerConsumer name in log messages -#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) static const mat4 mtxIdentity; diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 11a9e19db8..f12d7b6a17 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -140,18 +140,6 @@ cc_test { "libgtest", ], sanitize: { - // By using the address sanitizer, we not only uncover any issues - // with the test, but also any issues with the code under test. - // - // Note: If you get an runtime link error like: - // - // CANNOT LINK EXECUTABLE "/data/local/tmp/libcompositionengine_test": library "libclang_rt.asan-aarch64-android.so" not found - // - // it is because the address sanitizer shared objects are not installed - // by default in the system image. - // - // You can either "make dist tests" before flashing, or set this - // option to false temporarily. - address: true, + hwaddress: true, }, } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index f439caf9e1..8dab6ce61b 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -34,7 +34,7 @@ LayerState::LayerState(compositionengine::OutputLayer* layer) [](const mat4& mat) { using namespace std::string_literals; std::vector<std::string> split = - base::Split(std::string(mat.asString().string()), "\n"s); + base::Split(std::string(mat.asString().c_str()), "\n"s); split.pop_back(); // Strip the last (empty) line return split; }}) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 54133d92b0..5e6cade56f 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -216,32 +216,32 @@ void Planner::dump(const Vector<String16>& args, std::string& result) { base::StringAppendF(&result, "Expected two layer stack hashes, e.g. '--planner %s " "<left_hash> <right_hash>'\n", - command.string()); + command.c_str()); return; } if (args.size() > 4) { base::StringAppendF(&result, "Too many arguments found, expected '--planner %s <left_hash> " "<right_hash>'\n", - command.string()); + command.c_str()); return; } const String8 leftHashString(args[2]); size_t leftHash = 0; - int fieldsRead = sscanf(leftHashString.string(), "%zx", &leftHash); + int fieldsRead = sscanf(leftHashString.c_str(), "%zx", &leftHash); if (fieldsRead != 1) { base::StringAppendF(&result, "Failed to parse %s as a size_t\n", - leftHashString.string()); + leftHashString.c_str()); return; } const String8 rightHashString(args[3]); size_t rightHash = 0; - fieldsRead = sscanf(rightHashString.string(), "%zx", &rightHash); + fieldsRead = sscanf(rightHashString.c_str(), "%zx", &rightHash); if (fieldsRead != 1) { base::StringAppendF(&result, "Failed to parse %s as a size_t\n", - rightHashString.string()); + rightHashString.c_str()); return; } @@ -252,22 +252,22 @@ void Planner::dump(const Vector<String16>& args, std::string& result) { if (args.size() < 3) { base::StringAppendF(&result, "Expected a layer stack hash, e.g. '--planner %s <hash>'\n", - command.string()); + command.c_str()); return; } if (args.size() > 3) { base::StringAppendF(&result, "Too many arguments found, expected '--planner %s <hash>'\n", - command.string()); + command.c_str()); return; } const String8 hashString(args[2]); size_t hash = 0; - const int fieldsRead = sscanf(hashString.string(), "%zx", &hash); + const int fieldsRead = sscanf(hashString.c_str(), "%zx", &hash); if (fieldsRead != 1) { base::StringAppendF(&result, "Failed to parse %s as a size_t\n", - hashString.string()); + hashString.c_str()); return; } @@ -279,20 +279,20 @@ void Planner::dump(const Vector<String16>& args, std::string& result) { } else if (command == "--similar" || command == "-s") { if (args.size() < 3) { base::StringAppendF(&result, "Expected a plan string, e.g. '--planner %s <plan>'\n", - command.string()); + command.c_str()); return; } if (args.size() > 3) { base::StringAppendF(&result, "Too many arguments found, expected '--planner %s <plan>'\n", - command.string()); + command.c_str()); return; } const String8 planString(args[2]); - std::optional<Plan> plan = Plan::fromString(std::string(planString.string())); + std::optional<Plan> plan = Plan::fromString(std::string(planString.c_str())); if (!plan) { - base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.string()); + base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.c_str()); return; } @@ -302,7 +302,7 @@ void Planner::dump(const Vector<String16>& args, std::string& result) { } else if (command == "--layers" || command == "-l") { mFlattener.dumpLayers(result); } else { - base::StringAppendF(&result, "Unknown command '%s'\n\n", command.string()); + base::StringAppendF(&result, "Unknown command '%s'\n\n", command.c_str()); dumpUsage(result); } return; diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index 4e7da829f2..0aee7d497c 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -1,6 +1,10 @@ +# Bug component: 1075131 + adyabr@google.com alecmouri@google.com chaviw@google.com +domlaskowski@google.com +jreck@google.com lpy@google.com pdwilliams@google.com racarr@google.com diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8c46515bf1..314b4cd57b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5141,7 +5141,7 @@ void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) if (args.size() > 1) { const auto name = String8(args[1]); mCurrentState.traverseInZOrder([&](Layer* layer) { - if (layer->getName() == name.string()) { + if (layer->getName() == name.c_str()) { layer->dumpFrameStats(result); } }); @@ -5155,7 +5155,7 @@ void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) { const auto name = clearAll ? String8() : String8(args[1]); mCurrentState.traverse([&](Layer* layer) { - if (clearAll || layer->getName() == name.string()) { + if (clearAll || layer->getName() == name.c_str()) { layer->clearFrameStats(); } }); @@ -6755,7 +6755,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon( if (captureListener) { // TODO: The future returned by std::async blocks the main thread. Return a chain of // futures to the Binder thread instead. - std::async([=]() mutable { + (void)std::async([=]() mutable { ATRACE_NAME("captureListener is nonnull!"); auto fenceResult = renderFuture.get(); // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 0782fef8ea..bace6cc6a6 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -559,7 +559,7 @@ void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32 DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId)); DispSurfaceChange* surfaceChange(dispChange->mutable_surface()); surfaceChange->set_buffer_queue_id(bufferQueueId); - surfaceChange->set_buffer_queue_name(surface->getConsumerName().string()); + surfaceChange->set_buffer_queue_name(surface->getConsumerName().c_str()); } else { ALOGE("invalid graphic buffer producer received while tracing a display change (%s)", diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 867a1985bd..c679b14d7b 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -278,7 +278,7 @@ private: // MessageQueue overrides: void scheduleFrame() override {} - void postMessage(sp<MessageHandler>&&) override {} + void postMessage(sp<MessageHandler>&& handler) override { handler->handleMessage(Message()); } }; } // namespace scheduler diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 28e8b8c78b..7a98bc27a9 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -359,7 +359,7 @@ void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) { } void SurfaceInterceptorTest::blurRegionsUpdate(Transaction& t) { - BLUR_REGIONS_UPDATE.empty(); + BLUR_REGIONS_UPDATE.clear(); BLUR_REGIONS_UPDATE.push_back(BlurRegion()); t.setBlurRegions(mBGSurfaceControl, BLUR_REGIONS_UPDATE); } @@ -775,7 +775,7 @@ bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment, } bool SurfaceInterceptorTest::displayCreationFound(const Increment& increment, bool foundDisplay) { - bool isMatch(increment.display_creation().name() == DISPLAY_NAME.string() && + bool isMatch(increment.display_creation().name() == DISPLAY_NAME.c_str() && !increment.display_creation().is_secure()); if (isMatch && !foundDisplay) { foundDisplay = true; @@ -816,7 +816,7 @@ bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace, break; case Increment::IncrementCase::kDisplayDeletion: // Find the id of created display. - targetId = getDisplayId(trace, DISPLAY_NAME.string()); + targetId = getDisplayId(trace, DISPLAY_NAME.c_str()); foundIncrement = displayDeletionFound(increment, targetId, foundIncrement); break; default: diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index f7d34ac5da..e20818cd56 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -46,7 +46,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) { const auto& display = getCurrentDisplayState(displayToken); EXPECT_TRUE(display.isVirtual()); EXPECT_FALSE(display.isSecure); - EXPECT_EQ(name.string(), display.displayName); + EXPECT_EQ(name.c_str(), display.displayName); // -------------------------------------------------------------------- // Cleanup conditions @@ -81,7 +81,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { const auto& display = getCurrentDisplayState(displayToken); EXPECT_TRUE(display.isVirtual()); EXPECT_TRUE(display.isSecure); - EXPECT_EQ(name.string(), display.displayName); + EXPECT_EQ(name.c_str(), display.displayName); // -------------------------------------------------------------------- // Cleanup conditions diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index f879430db0..b75cf085cb 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -161,7 +161,7 @@ public: String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", x, y, r, g, b, pixel[0], pixel[1], pixel[2])); - EXPECT_EQ(String8(), err) << err.string(); + EXPECT_EQ(String8(), err) << err.c_str(); } } diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS index d073e2bd46..031b333fab 100644 --- a/services/vibratorservice/OWNERS +++ b/services/vibratorservice/OWNERS @@ -1 +1,3 @@ +# Bug component: 345036 + include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp index 523f890ce7..d0a9da1ff5 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp +++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp @@ -113,7 +113,7 @@ status_t VirtualTouchpadService::dump( static_cast<long>(client_pid_)); touchpad_->dumpInternal(result); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return OK; } diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index a99355f047..f92078d8dc 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -747,6 +747,17 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (strcmp(name, props.extensionName) != 0) continue; + // Ignore duplicate extensions (see: b/288929054) + bool duplicate_entry = false; + for (uint32_t j = 0; j < filter.name_count; j++) { + if (strcmp(name, filter.names[j]) == 0) { + duplicate_entry = true; + break; + } + } + if (duplicate_entry == true) + continue; + filter.names[filter.name_count++] = name; if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp index a14fed222a..d059f8fe4c 100644 --- a/vulkan/libvulkan/layers_extensions.cpp +++ b/vulkan/libvulkan/layers_extensions.cpp @@ -23,6 +23,7 @@ #include <dlfcn.h> #include <string.h> #include <sys/prctl.h> +#include <unistd.h> #include <mutex> #include <string> @@ -362,6 +363,7 @@ template <typename Functor> void ForEachFileInZip(const std::string& zipname, const std::string& dir_in_zip, Functor functor) { + static const size_t kPageSize = getpagesize(); int32_t err; ZipArchiveHandle zip = nullptr; if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) { @@ -389,7 +391,7 @@ void ForEachFileInZip(const std::string& zipname, // the APK. Loading still may fail for other reasons, but this at least // lets us avoid failed-to-load log messages in the typical case of // compressed and/or unaligned libraries. - if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0) + if (entry.method != kCompressStored || entry.offset % kPageSize != 0) continue; functor(filename); } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index c46036a5e2..570c01eb4b 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -16,6 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <aidl/android/hardware/graphics/common/PixelFormat.h> #include <android/hardware/graphics/common/1.0/types.h> #include <grallocusage/GrallocUsageConversion.h> #include <graphicsenv/GraphicsEnv.h> @@ -25,8 +26,6 @@ #include <sync/sync.h> #include <system/window.h> #include <ui/BufferQueueDefs.h> -#include <ui/DebugUtils.h> -#include <ui/PixelFormat.h> #include <utils/StrongPointer.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -37,6 +36,7 @@ #include "driver.h" +using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; using android::hardware::graphics::common::V1_0::BufferUsage; namespace vulkan { @@ -489,27 +489,27 @@ void copy_ready_timings(Swapchain& swapchain, *count = num_copied; } -android::PixelFormat GetNativePixelFormat(VkFormat format) { - android::PixelFormat native_format = android::PIXEL_FORMAT_RGBA_8888; +PixelFormat GetNativePixelFormat(VkFormat format) { + PixelFormat native_format = PixelFormat::RGBA_8888; switch (format) { case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_SRGB: - native_format = android::PIXEL_FORMAT_RGBA_8888; + native_format = PixelFormat::RGBA_8888; break; case VK_FORMAT_R5G6B5_UNORM_PACK16: - native_format = android::PIXEL_FORMAT_RGB_565; + native_format = PixelFormat::RGB_565; break; case VK_FORMAT_R16G16B16A16_SFLOAT: - native_format = android::PIXEL_FORMAT_RGBA_FP16; + native_format = PixelFormat::RGBA_FP16; break; case VK_FORMAT_A2B10G10R10_UNORM_PACK32: - native_format = android::PIXEL_FORMAT_RGBA_1010102; + native_format = PixelFormat::RGBA_1010102; break; case VK_FORMAT_R8_UNORM: - native_format = android::PIXEL_FORMAT_R_8; + native_format = PixelFormat::R_8; break; case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: - native_format = android::PIXEL_FORMAT_RGBA_10101010; + native_format = PixelFormat::RGBA_10101010; break; default: ALOGV("unsupported swapchain format %d", format); @@ -518,7 +518,8 @@ android::PixelFormat GetNativePixelFormat(VkFormat format) { return native_format; } -android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { +android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace, + PixelFormat pixelFormat) { switch (colorspace) { case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: return HAL_DATASPACE_V0_SRGB; @@ -537,7 +538,14 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { case VK_COLOR_SPACE_BT709_NONLINEAR_EXT: return HAL_DATASPACE_V0_SRGB; case VK_COLOR_SPACE_BT2020_LINEAR_EXT: - return HAL_DATASPACE_BT2020_LINEAR; + if (pixelFormat == PixelFormat::RGBA_FP16) { + return static_cast<android_dataspace>( + HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_LINEAR | + HAL_DATASPACE_RANGE_EXTENDED); + } else { + return HAL_DATASPACE_BT2020_LINEAR; + } case VK_COLOR_SPACE_HDR10_ST2084_EXT: return static_cast<android_dataspace>( HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 | @@ -547,9 +555,7 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 | HAL_DATASPACE_RANGE_FULL); case VK_COLOR_SPACE_HDR10_HLG_EXT: - return static_cast<android_dataspace>( - HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG | - HAL_DATASPACE_RANGE_FULL); + return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG); case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT: return static_cast<android_dataspace>( HAL_DATASPACE_STANDARD_ADOBE_RGB | @@ -1256,10 +1262,10 @@ VkResult CreateSwapchainKHR(VkDevice device, if (!allocator) allocator = &GetData(device).allocator; - android::PixelFormat native_pixel_format = + PixelFormat native_pixel_format = GetNativePixelFormat(create_info->imageFormat); android_dataspace native_dataspace = - GetNativeDataspace(create_info->imageColorSpace); + GetNativeDataspace(create_info->imageColorSpace, native_pixel_format); if (native_dataspace == HAL_DATASPACE_UNKNOWN) { ALOGE( "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) " @@ -1351,10 +1357,11 @@ VkResult CreateSwapchainKHR(VkDevice device, const auto& dispatch = GetData(device).driver; - err = native_window_set_buffers_format(window, native_pixel_format); + err = native_window_set_buffers_format( + window, static_cast<int>(native_pixel_format)); if (err != android::OK) { ALOGE("native_window_set_buffers_format(%s) failed: %s (%d)", - decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err); + toString(native_pixel_format).c_str(), strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } |