diff options
73 files changed, 1025 insertions, 259 deletions
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl index bb3faaff79..668671760c 100644 --- a/aidl/gui/android/view/Surface.aidl +++ b/aidl/gui/android/view/Surface.aidl @@ -17,4 +17,4 @@ package android.view; -@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h"; +@JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h" rust_type "nativewindow::Surface"; diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 5719a09a16..cd4926ad50 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -313,12 +313,6 @@ static const char* k_traceClockPath = static const char* k_traceBufferSizePath = "buffer_size_kb"; -#if 0 -// TODO: Re-enable after stabilization -static const char* k_traceCmdlineSizePath = - "saved_cmdlines_size"; -#endif - static const char* k_tracingOverwriteEnablePath = "options/overwrite"; @@ -545,18 +539,6 @@ static bool setTraceBufferSizeKB(int size) return writeStr(k_traceBufferSizePath, str); } -#if 0 -// TODO: Re-enable after stabilization -// Set the default size of cmdline hashtable -static bool setCmdlineSize() -{ - if (fileExists(k_traceCmdlineSizePath)) { - return writeStr(k_traceCmdlineSizePath, "8192"); - } - return true; -} -#endif - // Set the clock to the best available option while tracing. Use 'boot' if it's // available; otherwise, use 'mono'. If neither are available use 'global'. // Any write to the trace_clock sysfs file will reset the buffer, so only @@ -870,8 +852,6 @@ static bool setUpKernelTracing() ok &= setCategoriesEnableFromFile(g_categoriesFile); ok &= setTraceOverwriteEnable(g_traceOverwrite); ok &= setTraceBufferSizeKB(g_traceBufferSizeKB); - // TODO: Re-enable after stabilization - //ok &= setCmdlineSize(); ok &= setClock(); ok &= setPrintTgidEnableIfPresent(true); ok &= setKernelTraceFuncs(g_kernelTraceFuncs); diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 3e6d2e01f8..9b357e7163 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -13,6 +13,8 @@ on late-init # Access control to these files is now entirely in selinux policy. chmod 0666 /sys/kernel/debug/tracing/trace_clock chmod 0666 /sys/kernel/tracing/trace_clock + chmod 0666 /sys/kernel/debug/tracing/buffer_percent + chmod 0666 /sys/kernel/tracing/buffer_percent chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb chmod 0666 /sys/kernel/tracing/buffer_size_kb chmod 0666 /sys/kernel/debug/tracing/options/overwrite diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 71a87403d5..9399c73b2a 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -4029,24 +4029,37 @@ binder::Status InstalldNativeService::enableFsverity(const sp<IFsveritySetupAuth 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. + // Authenticate to check the targeting file is the same inode as the authFd. With O_PATH, we + // prevent a malicious client from blocking installd by providing a path to FIFO. After the + // authentication, the actual open is safe. 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)); + unique_fd pathFd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_PATH)); + // Returns a constant errno to avoid one app probing file existence of the others, before the + // authentication is done. + const int kFixedErrno = EPERM; + if (pathFd.get() < 0) { + PLOG(DEBUG) << "Failed to open the path"; + *_aidl_return = kFixedErrno; + return ok(); + } + std::string procFdPath(StringPrintf("/proc/self/fd/%d", pathFd.get())); struct stat stFromPath; - if (fstat(rfd.get(), &stFromPath) < 0) { - *_aidl_return = errno; + if (stat(procFdPath.c_str(), &stFromPath) < 0) { + PLOG(DEBUG) << "Failed to stat proc fd " << pathFd.get() << " -> " << filePath; + *_aidl_return = kFixedErrno; return ok(); } + auto authTokenInstance = sp<FsveritySetupAuthToken>::cast(authTokenBinder); if (!authTokenInstance->isSameStat(stFromPath)) { LOG(DEBUG) << "FD authentication failed"; - *_aidl_return = EPERM; + *_aidl_return = kFixedErrno; return ok(); } + unique_fd rfd(open(procFdPath.c_str(), O_RDONLY | O_CLOEXEC)); fsverity_enable_arg arg = {}; arg.version = 1; arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index f2b578a8d2..023491fc10 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -194,6 +194,12 @@ static bool exists_renamed_deleted_dir(const std::string& rootDirectory) { }); } +static void unlink_path(const std::string& path) { + if (unlink(path.c_str()) < 0) { + PLOG(DEBUG) << "Failed to unlink " + path; + } +} + class ServiceTest : public testing::Test { protected: InstalldNativeService* service; @@ -555,7 +561,7 @@ protected: 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()); }); + UniqueFile raii(/*fd=*/-1, path, &unlink_path); // Expect to fs-verity setup to succeed sp<IFsveritySetupAuthToken> authToken; @@ -573,7 +579,7 @@ TEST_F(FsverityTest, enableFsverity) { 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()); }); + UniqueFile raii(/*fd=*/-1, path, &unlink_path); // Verity null auth token fails sp<IFsveritySetupAuthToken> authToken; @@ -586,7 +592,7 @@ TEST_F(FsverityTest, enableFsverity_nullAuthToken) { 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()); }); + UniqueFile raii(/*fd=*/-1, path, &unlink_path); // Expect to fs-verity setup to succeed sp<IFsveritySetupAuthToken> authToken; @@ -597,17 +603,36 @@ TEST_F(FsverityTest, enableFsverity_differentFile) { // 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()); }); + UniqueFile raii2(/*fd=*/-1, anotherPath, &unlink_path); 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, enableFsverity_errnoBeforeAuthenticated) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, &unlink_path); + + // 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 errno before the fd authentication is constant (EPERM) + int32_t errno_local; + status = service->enableFsverity(authToken, path + "-non-exist", "fake.package.name", + &errno_local); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(errno_local, EPERM); +} + 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()); }); + UniqueFile raii(/*fd=*/-1, path, &unlink_path); // Expect the fs-verity setup to fail sp<IFsveritySetupAuthToken> authToken; @@ -619,7 +644,7 @@ 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()); }); + UniqueFile raii(/*fd=*/-1, path, &unlink_path); // Expect the fs-verity setup to fail sp<IFsveritySetupAuthToken> authToken; diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp index 6115da75b2..5cdcb23d13 100644 --- a/cmds/lshal/Lshal.cpp +++ b/cmds/lshal/Lshal.cpp @@ -232,6 +232,11 @@ Status Lshal::main(const Arg &arg) { return static_cast<HelpCommand*>(help)->usageOfCommand(mCommand); } + // After Lshal::main() finishes, caller may call _exit(), causing debug + // information to prematurely ends. Hence flush(). + err().flush(); + out().flush(); + return status; } diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h index 7cffcf8193..1576486c1d 100644 --- a/cmds/lshal/NullableOStream.h +++ b/cmds/lshal/NullableOStream.h @@ -59,6 +59,11 @@ public: operator bool() const { // NOLINT(google-explicit-constructor) return mOs != nullptr; } + void flush() { + if (mOs) { + mOs->flush(); + } + } private: template<typename> friend class NullableOStream; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index e00c2a2b5a..3897197bd5 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -95,6 +95,16 @@ cc_test { static_libs: ["libgmock"], } +cc_test_host { + name: "servicemanager_unittest", + test_suites: ["general-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "ServiceManagerUnittest.cpp", + ], + static_libs: ["libgmock"], +} + cc_fuzz { name: "servicemanager_fuzzer", defaults: [ diff --git a/cmds/servicemanager/NameUtil.h b/cmds/servicemanager/NameUtil.h new file mode 100644 index 0000000000..b08093960d --- /dev/null +++ b/cmds/servicemanager/NameUtil.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#pragma once + +#include <string> +#include <string_view> + +#include <android-base/strings.h> + +namespace android { + +#ifndef VENDORSERVICEMANAGER + +struct NativeName { + std::string package; + std::string instance; + + // Parse {package}/{instance} + static bool fill(std::string_view name, NativeName* nname) { + size_t slash = name.find('/'); + if (slash == std::string_view::npos) { + return false; + } + // no extra slashes + if (name.find('/', slash + 1) != std::string_view::npos) { + return false; + } + // every part should be non-empty + if (slash == 0 || slash + 1 == name.size()) { + return false; + } + // no dots in package + if (name.rfind('.', slash) != std::string_view::npos) { + return false; + } + nname->package = name.substr(0, slash); + nname->instance = name.substr(slash + 1); + return true; + } +}; + +#endif + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 77989d148b..bf85e61583 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -35,6 +35,8 @@ #include <vintf/constants.h> #endif // !VENDORSERVICEMANAGER +#include "NameUtil.h" + using ::android::binder::Status; using ::android::internal::Stability; @@ -84,6 +86,10 @@ static bool forEachManifest(const std::function<bool(const ManifestWithDescripti return false; } +static std::string getNativeInstanceName(const vintf::ManifestInstance& instance) { + return instance.package() + "/" + instance.instance(); +} + struct AidlName { std::string package; std::string iface; @@ -105,7 +111,26 @@ struct AidlName { } }; +static std::string getAidlInstanceName(const vintf::ManifestInstance& instance) { + return instance.package() + "." + instance.interface() + "/" + instance.instance(); +} + static bool isVintfDeclared(const std::string& name) { + NativeName nname; + if (NativeName::fill(name, &nname)) { + bool found = forEachManifest([&](const ManifestWithDescription& mwd) { + if (mwd.manifest->hasNativeInstance(nname.package, nname.instance)) { + ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description); + return true; // break + } + return false; // continue + }); + if (!found) { + ALOGI("Could not find %s in the VINTF manifest.", name.c_str()); + } + return found; + } + AidlName aname; if (!AidlName::fill(name, &aname)) return false; @@ -144,13 +169,31 @@ static bool isVintfDeclared(const std::string& name) { } static std::optional<std::string> getVintfUpdatableApex(const std::string& name) { + NativeName nname; + if (NativeName::fill(name, &nname)) { + std::optional<std::string> updatableViaApex; + + forEachManifest([&](const ManifestWithDescription& mwd) { + bool cont = mwd.manifest->forEachInstance([&](const auto& manifestInstance) { + if (manifestInstance.format() != vintf::HalFormat::NATIVE) return true; + if (manifestInstance.package() != nname.package) return true; + if (manifestInstance.instance() != nname.instance) return true; + updatableViaApex = manifestInstance.updatableViaApex(); + return false; // break (libvintf uses opposite convention) + }); + return !cont; + }); + + return updatableViaApex; + } + AidlName aname; if (!AidlName::fill(name, &aname)) return std::nullopt; std::optional<std::string> updatableViaApex; forEachManifest([&](const ManifestWithDescription& mwd) { - mwd.manifest->forEachInstance([&](const auto& manifestInstance) { + bool cont = mwd.manifest->forEachInstance([&](const auto& manifestInstance) { if (manifestInstance.format() != vintf::HalFormat::AIDL) return true; if (manifestInstance.package() != aname.package) return true; if (manifestInstance.interface() != aname.iface) return true; @@ -158,31 +201,31 @@ static std::optional<std::string> getVintfUpdatableApex(const std::string& name) updatableViaApex = manifestInstance.updatableViaApex(); return false; // break (libvintf uses opposite convention) }); - if (updatableViaApex.has_value()) return true; // break (found match) - return false; // continue + return !cont; }); return updatableViaApex; } -static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) { - std::vector<std::string> instances; +static std::vector<std::string> getVintfUpdatableNames(const std::string& apexName) { + std::vector<std::string> names; forEachManifest([&](const ManifestWithDescription& mwd) { mwd.manifest->forEachInstance([&](const auto& manifestInstance) { - if (manifestInstance.format() == vintf::HalFormat::AIDL && - manifestInstance.updatableViaApex().has_value() && + if (manifestInstance.updatableViaApex().has_value() && manifestInstance.updatableViaApex().value() == apexName) { - std::string aname = manifestInstance.package() + "." + - manifestInstance.interface() + "/" + manifestInstance.instance(); - instances.push_back(aname); + if (manifestInstance.format() == vintf::HalFormat::NATIVE) { + names.push_back(getNativeInstanceName(manifestInstance)); + } else if (manifestInstance.format() == vintf::HalFormat::AIDL) { + names.push_back(getAidlInstanceName(manifestInstance)); + } } return true; // continue (libvintf uses opposite convention) }); return false; // continue }); - return instances; + return names; } static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) { @@ -217,6 +260,18 @@ static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& n static std::vector<std::string> getVintfInstances(const std::string& interface) { size_t lastDot = interface.rfind('.'); if (lastDot == std::string::npos) { + // This might be a package for native instance. + std::vector<std::string> ret; + (void)forEachManifest([&](const ManifestWithDescription& mwd) { + auto instances = mwd.manifest->getNativeInstances(interface); + ret.insert(ret.end(), instances.begin(), instances.end()); + return false; // continue + }); + // If found, return it without error log. + if (!ret.empty()) { + return ret; + } + ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) " "but got: %s", interface.c_str()); @@ -594,20 +649,20 @@ Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& ape std::vector<std::string>* outReturn) { auto ctx = mAccess->getCallingContext(); - std::vector<std::string> apexUpdatableInstances; + std::vector<std::string> apexUpdatableNames; #ifndef VENDORSERVICEMANAGER - apexUpdatableInstances = getVintfUpdatableInstances(apexName); + apexUpdatableNames = getVintfUpdatableNames(apexName); #endif outReturn->clear(); - for (const std::string& instance : apexUpdatableInstances) { - if (mAccess->canFind(ctx, instance)) { - outReturn->push_back(instance); + for (const std::string& name : apexUpdatableNames) { + if (mAccess->canFind(ctx, name)) { + outReturn->push_back(name); } } - if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) { + if (outReturn->size() == 0 && apexUpdatableNames.size() != 0) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } diff --git a/cmds/servicemanager/ServiceManagerUnittest.cpp b/cmds/servicemanager/ServiceManagerUnittest.cpp new file mode 100644 index 0000000000..39d20b0025 --- /dev/null +++ b/cmds/servicemanager/ServiceManagerUnittest.cpp @@ -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. + */ + +#include <gtest/gtest.h> + +#include "NameUtil.h" + +namespace android { + +TEST(ServiceManager, NativeName) { + NativeName nname; + EXPECT_TRUE(NativeName::fill("mapper/default", &nname)); + EXPECT_EQ("mapper", nname.package); + EXPECT_EQ("default", nname.instance); +} + +TEST(ServiceManager, NativeName_Malformed) { + NativeName nname; + EXPECT_FALSE(NativeName::fill("mapper", &nname)); + EXPECT_FALSE(NativeName::fill("mapper/", &nname)); + EXPECT_FALSE(NativeName::fill("/default", &nname)); + EXPECT_FALSE(NativeName::fill("mapper/default/0", &nname)); + EXPECT_FALSE(NativeName::fill("aidl.like.IType/default", &nname)); +} + +} // namespace android diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index ae56cb0ed3..07908ba5b3 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -40,15 +40,12 @@ class BinderCallback : public LooperCallback { public: static sp<BinderCallback> setupTo(const sp<Looper>& looper) { sp<BinderCallback> cb = sp<BinderCallback>::make(); + cb->mLooper = looper; - int binder_fd = -1; - IPCThreadState::self()->setupPolling(&binder_fd); - LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd); + IPCThreadState::self()->setupPolling(&cb->mBinderFd); + LOG_ALWAYS_FATAL_IF(cb->mBinderFd < 0, "Failed to setupPolling: %d", cb->mBinderFd); - int ret = looper->addFd(binder_fd, - Looper::POLL_CALLBACK, - Looper::EVENT_INPUT, - cb, + int ret = looper->addFd(cb->mBinderFd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr /*data*/); LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper"); @@ -59,13 +56,26 @@ public: IPCThreadState::self()->handlePolledCommands(); return 1; // Continue receiving callbacks. } + + void repoll() { + if (!mLooper->repoll(mBinderFd)) { + ALOGE("Failed to repoll binder FD."); + } + } + +private: + sp<Looper> mLooper; + int mBinderFd = -1; }; // LooperCallback for IClientCallback class ClientCallbackCallback : public LooperCallback { public: - static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { + static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, + const sp<ServiceManager>& manager, + sp<BinderCallback> binderCallback) { sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager); + cb->mBinderCallback = binderCallback; int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); @@ -102,12 +112,15 @@ public: } mManager->handleClientCallbacks(); + mBinderCallback->repoll(); // b/316829336 + return 1; // Continue receiving callbacks. } private: friend sp<ClientCallbackCallback>; ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} sp<ServiceManager> mManager; + sp<BinderCallback> mBinderCallback; }; int main(int argc, char** argv) { @@ -139,8 +152,8 @@ int main(int argc, char** argv) { sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); - BinderCallback::setupTo(looper); - ClientCallbackCallback::setupTo(looper, manager); + sp<BinderCallback> binderCallback = BinderCallback::setupTo(looper); + ClientCallbackCallback::setupTo(looper, manager, binderCallback); #ifndef VENDORSERVICEMANAGER if (!SetProperty("servicemanager.ready", "true")) { diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index 97e500d0a7..b57505302c 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -361,6 +361,24 @@ TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) { EXPECT_EQ(std::vector<std::string>{}, names); } +TEST(Vintf, IsDeclared_native) { + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; + + auto sm = getPermissiveServiceManager(); + bool declared = false; + EXPECT_TRUE(sm->isDeclared("mapper/minigbm", &declared).isOk()); + EXPECT_TRUE(declared); +} + +TEST(Vintf, GetDeclaredInstances_native) { + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; + + auto sm = getPermissiveServiceManager(); + std::vector<std::string> instances; + EXPECT_TRUE(sm->getDeclaredInstances("mapper", &instances).isOk()); + EXPECT_EQ(std::vector<std::string>{"minigbm"}, instances); +} + class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index ae0fb018ef..84ff9d74ef 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -320,6 +320,24 @@ cc_defaults { "ServiceManagerHost.cpp", ], }, + android: { + shared_libs: [ + "libapexsupport", + "libvndksupport", + ], + }, + recovery: { + exclude_shared_libs: [ + "libapexsupport", + "libvndksupport", + ], + }, + native_bridge: { + exclude_shared_libs: [ + "libapexsupport", + "libvndksupport", + ], + }, }, cflags: [ "-DBINDER_WITH_KERNEL_IPC", @@ -646,9 +664,7 @@ cc_library { // Do not expand the visibility. visibility: [ ":__subpackages__", - "//packages/modules/Virtualization/javalib/jni", - "//packages/modules/Virtualization/vm_payload", - "//packages/modules/Virtualization/demo_native", + "//packages/modules/Virtualization:__subpackages__", "//device/google/cuttlefish/shared/minidroid:__subpackages__", "//system/software_defined_vehicle:__subpackages__", ], diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index b92e504a9a..ef96f803c3 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -922,28 +922,10 @@ void IPCThreadState::decWeakHandle(int32_t handle) flushIfNeeded(); } -status_t IPCThreadState::attemptIncStrongHandle(int32_t handle) -{ -#if HAS_BC_ATTEMPT_ACQUIRE - LOG_REMOTEREFS("IPCThreadState::attemptIncStrongHandle(%d)\n", handle); - mOut.writeInt32(BC_ATTEMPT_ACQUIRE); - mOut.writeInt32(0); // xxx was thread priority - mOut.writeInt32(handle); - status_t result = UNKNOWN_ERROR; - - waitForResponse(NULL, &result); - -#if LOG_REFCOUNTS - ALOGV("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n", - handle, result == NO_ERROR ? "SUCCESS" : "FAILURE"); -#endif - - return result; -#else +status_t IPCThreadState::attemptIncStrongHandle(int32_t handle) { (void)handle; ALOGE("%s(%d): Not supported\n", __func__, handle); return INVALID_OPERATION; -#endif } void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder) diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index fe566fccb2..39573ec54d 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -40,6 +40,11 @@ #include "ServiceManagerHost.h" #endif +#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) && !defined(__ANDROID_NATIVE_BRIDGE__) +#include <android/apexsupport.h> +#include <vndksupport/linker.h> +#endif + #include "Static.h" namespace android { @@ -259,6 +264,27 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP } } +void* openDeclaredPassthroughHal(const String16& interface, const String16& instance, int flag) { +#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) && !defined(__ANDROID_NATIVE_BRIDGE__) + sp<IServiceManager> sm = defaultServiceManager(); + String16 name = interface + String16("/") + instance; + if (!sm->isDeclared(name)) { + return nullptr; + } + String16 libraryName = interface + String16(".") + instance + String16(".so"); + if (auto updatableViaApex = sm->updatableViaApex(name); updatableViaApex.has_value()) { + return AApexSupport_loadLibrary(String8(libraryName).c_str(), + String8(*updatableViaApex).c_str(), flag); + } + return android_load_sphal_library(String8(libraryName).c_str(), flag); +#else + (void)interface; + (void)instance; + (void)flag; + return nullptr; +#endif +} + #endif //__ANDROID_VNDK__ // ---------------------------------------------------------------------- diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 7de94e3c6c..fb2781be59 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -492,6 +492,7 @@ bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) { if (read(fd, &on, sizeof(on)) == -1) { ALOGE("%s: error reading to %s: %s", __func__, names[static_cast<int>(feature)], strerror(errno)); + close(fd); return false; } close(fd); diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp index 525ba2e9b9..de2a69f7cf 100644 --- a/libs/binder/RecordedTransaction.cpp +++ b/libs/binder/RecordedTransaction.cpp @@ -114,8 +114,8 @@ static_assert(PADDING8(8) == 0); RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept { mData = t.mData; - mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); - mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); + mSentDataOnly.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); + mReplyDataOnly.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); } std::optional<RecordedTransaction> RecordedTransaction::fromDetails( @@ -136,12 +136,21 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails( return std::nullopt; } - if (t.mSent.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) { + if (const auto* kernelFields = dataParcel.maybeKernelFields()) { + for (size_t i = 0; i < kernelFields->mObjectsSize; i++) { + uint64_t offset = kernelFields->mObjects[i]; + t.mData.mSentObjectData.push_back(offset); + } + } + + if (t.mSentDataOnly.setData(dataParcel.data(), dataParcel.dataBufferSize()) != + android::NO_ERROR) { ALOGE("Failed to set sent parcel data."); return std::nullopt; } - if (t.mReply.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) { + if (t.mReplyDataOnly.setData(replyParcel.data(), replyParcel.dataBufferSize()) != + android::NO_ERROR) { ALOGE("Failed to set reply parcel data."); return std::nullopt; } @@ -154,6 +163,7 @@ enum { DATA_PARCEL_CHUNK = 2, REPLY_PARCEL_CHUNK = 3, INTERFACE_NAME_CHUNK = 4, + DATA_PARCEL_OBJECT_CHUNK = 5, END_CHUNK = 0x00ffffff, }; @@ -265,21 +275,30 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; } case DATA_PARCEL_CHUNK: { - if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap), - chunk.dataSize) != android::NO_ERROR) { + if (t.mSentDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap), + chunk.dataSize) != android::NO_ERROR) { ALOGE("Failed to set sent parcel data."); return std::nullopt; } break; } case REPLY_PARCEL_CHUNK: { - if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap), - chunk.dataSize) != android::NO_ERROR) { + if (t.mReplyDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap), + chunk.dataSize) != android::NO_ERROR) { ALOGE("Failed to set reply parcel data."); return std::nullopt; } break; } + case DATA_PARCEL_OBJECT_CHUNK: { + const uint64_t* objects = reinterpret_cast<const uint64_t*>(payloadMap); + size_t metaDataSize = (chunk.dataSize / sizeof(uint64_t)); + ALOGI("Total objects found in saved parcel %zu", metaDataSize); + for (size_t index = 0; index < metaDataSize; ++index) { + t.mData.mSentObjectData.push_back(objects[index]); + } + break; + } case END_CHUNK: break; default: @@ -343,14 +362,26 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { return UNKNOWN_ERROR; } - if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataBufferSize(), mSent.data())) { + if (NO_ERROR != + writeChunk(fd, DATA_PARCEL_CHUNK, mSentDataOnly.dataBufferSize(), mSentDataOnly.data())) { ALOGE("Failed to write sent Parcel to fd %d", fd.get()); return UNKNOWN_ERROR; } - if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataBufferSize(), mReply.data())) { + + if (NO_ERROR != + writeChunk(fd, REPLY_PARCEL_CHUNK, mReplyDataOnly.dataBufferSize(), + mReplyDataOnly.data())) { ALOGE("Failed to write reply Parcel to fd %d", fd.get()); return UNKNOWN_ERROR; } + + if (NO_ERROR != + writeChunk(fd, DATA_PARCEL_OBJECT_CHUNK, mData.mSentObjectData.size() * sizeof(uint64_t), + reinterpret_cast<const uint8_t*>(mData.mSentObjectData.data()))) { + ALOGE("Failed to write sent parcel object metadata to fd %d", fd.get()); + return UNKNOWN_ERROR; + } + if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) { ALOGE("Failed to write end chunk to fd %d", fd.get()); return UNKNOWN_ERROR; @@ -384,10 +415,14 @@ uint32_t RecordedTransaction::getVersion() const { return mData.mHeader.version; } +const std::vector<uint64_t>& RecordedTransaction::getObjectOffsets() const { + return mData.mSentObjectData; +} + const Parcel& RecordedTransaction::getDataParcel() const { - return mSent; + return mSentDataOnly; } const Parcel& RecordedTransaction::getReplyParcel() const { - return mReply; + return mReplyDataOnly; } diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 55167a7db0..486bdfba78 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -207,6 +207,8 @@ status_t getService(const String16& name, sp<INTERFACE>* outService) return NAME_NOT_FOUND; } +void* openDeclaredPassthroughHal(const String16& interface, const String16& instance, int flag); + bool checkCallingPermission(const String16& permission); bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid); diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 09da6e3c4a..d7096d8a75 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -55,6 +55,9 @@ class String8; class TextOutput; namespace binder { class Status; +namespace debug { +class RecordedTransaction; +} } class Parcel { @@ -1443,6 +1446,9 @@ private: // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference // this size_t getBlobAshmemSize() const; + + // Needed so that we can save object metadata to the disk + friend class android::binder::debug::RecordedTransaction; }; // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/RecordedTransaction.h b/libs/binder/include/binder/RecordedTransaction.h index 505c1992b9..f0bee7f39e 100644 --- a/libs/binder/include/binder/RecordedTransaction.h +++ b/libs/binder/include/binder/RecordedTransaction.h @@ -50,6 +50,7 @@ public: uint32_t getVersion() const; const Parcel& getDataParcel() const; const Parcel& getReplyParcel() const; + const std::vector<uint64_t>& getObjectOffsets() const; private: RecordedTransaction() = default; @@ -75,10 +76,11 @@ private: struct MovableData { // movable TransactionHeader mHeader; std::string mInterfaceName; + std::vector<uint64_t> mSentObjectData; /* Object Offsets */ }; MovableData mData; - Parcel mSent; - Parcel mReply; + Parcel mSentDataOnly; + Parcel mReplyDataOnly; }; } // namespace binder::debug diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 316a79cfee..a905dff4b1 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -243,6 +243,20 @@ void AServiceManager_getUpdatableApexName(const char* instance, void* context, __INTRODUCED_IN(__ANDROID_API_U__); /** + * Opens a declared passthrough HAL. + * + * \param instance identifier of the passthrough service (e.g. "mapper") + * \param instance identifier of the implemenatation (e.g. "default") + * \param flag passed to dlopen() + * + * \return the result of dlopen of the specified HAL + */ +void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance, + int flag) + // TODO(b/302113279) use __INTRODUCED_LLNDK for vendor variants + __INTRODUCED_IN(__ANDROID_API_V__); + +/** * Prevent lazy services without client from shutting down their process * * This should only be used if it is every eventually set to false. If a diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 0843a8e648..de624e44f6 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -204,6 +204,7 @@ LIBBINDER_NDK35 { # introduced=VanillaIceCream APersistableBundle_getDoubleVectorKeys; APersistableBundle_getStringVectorKeys; APersistableBundle_getPersistableBundleKeys; + AServiceManager_openDeclaredPassthroughHal; # systemapi llndk }; LIBBINDER_NDK_PLATFORM { diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index 3bfdc59ec2..5529455cc6 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -200,6 +200,13 @@ void AServiceManager_getUpdatableApexName(const char* instance, void* context, callback(String8(updatableViaApex.value()).c_str(), context); } } +void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance, + int flag) { + LOG_ALWAYS_FATAL_IF(interface == nullptr, "interface == nullptr"); + LOG_ALWAYS_FATAL_IF(instance == nullptr, "instance == nullptr"); + + return openDeclaredPassthroughHal(String16(interface), String16(instance), flag); +} void AServiceManager_forceLazyServicesPersist(bool persist) { auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance(); serviceRegistrar.forcePersist(persist); diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index cab1a60370..966ec959b6 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -984,7 +984,7 @@ int main(int argc, char* argv[]) { return generatedFlaggedService(test_flags, kBinderNdkUnitTestServiceFlagged); } - ABinderProcess_setThreadPoolMaxThreadCount(1); // to receive death notifications/callbacks + ABinderProcess_setThreadPoolMaxThreadCount(0); ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index dd2be94a76..2f0987fd1a 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -69,10 +69,14 @@ cc_test { cc_test { name: "binderRecordReplayTest", srcs: ["binderRecordReplayTest.cpp"], + cflags: [ + "-DBINDER_WITH_KERNEL_IPC", + ], shared_libs: [ "libbinder", "libcutils", "libutils", + "liblog", ], static_libs: [ "binderRecordReplayTestIface-cpp", @@ -96,6 +100,14 @@ aidl_interface { enabled: true, platform_apis: true, }, + + // TODO: switch from FileDescriptor to ParcelFileDescriptor + ndk: { + enabled: false, + }, + rust: { + enabled: false, + }, }, } diff --git a/libs/binder/tests/IBinderRecordReplayTest.aidl b/libs/binder/tests/IBinderRecordReplayTest.aidl index bd6b03c6e0..29267e91c6 100644 --- a/libs/binder/tests/IBinderRecordReplayTest.aidl +++ b/libs/binder/tests/IBinderRecordReplayTest.aidl @@ -69,4 +69,10 @@ interface IBinderRecordReplayTest { void setSingleDataParcelableArray(in SingleDataParcelable[] input); SingleDataParcelable[] getSingleDataParcelableArray(); + + void setBinder(in IBinder binder); + IBinder getBinder(); + + void setFileDescriptor(in FileDescriptor fd); + FileDescriptor getFileDescriptor(); } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index cb1a1ee443..0ee96e7317 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -70,7 +70,7 @@ MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected } static ::testing::AssertionResult IsPageAligned(void *buf) { - if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0) + if (((unsigned long)buf & ((unsigned long)getpagesize() - 1)) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << buf << " is not page aligned"; diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 73c0a94ce2..b975fad2c9 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -24,7 +24,10 @@ #include <binder/RecordedTransaction.h> #include <binder/unique_fd.h> +#include <cutils/ashmem.h> + #include <fuzzbinder/libbinder_driver.h> +#include <fuzzbinder/random_binder.h> #include <fuzzer/FuzzedDataProvider.h> #include <fuzzseeds/random_parcel_seeds.h> @@ -37,6 +40,7 @@ using namespace android; using android::generateSeedsFromRecording; +using android::RandomBinder; using android::binder::borrowed_fd; using android::binder::Status; using android::binder::unique_fd; @@ -44,6 +48,7 @@ using android::binder::debug::RecordedTransaction; using parcelables::SingleDataParcelable; const String16 kServerName = String16("binderRecordReplay"); +extern std::string kRandomInterfaceName; #define GENERATE_GETTER_SETTER_PRIMITIVE(name, T) \ Status set##name(T input) { \ @@ -81,6 +86,7 @@ public: GENERATE_GETTER_SETTER(String, String16); GENERATE_GETTER_SETTER(SingleDataParcelable, SingleDataParcelable); + GENERATE_GETTER_SETTER(Binder, sp<IBinder>); GENERATE_GETTER_SETTER(BooleanArray, std::vector<bool>); GENERATE_GETTER_SETTER(ByteArray, std::vector<uint8_t>); @@ -91,12 +97,22 @@ public: GENERATE_GETTER_SETTER(DoubleArray, std::vector<double>); GENERATE_GETTER_SETTER(StringArray, std::vector<::android::String16>); GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>); + + Status setFileDescriptor(unique_fd input) { + mFd = std::move(unique_fd(dup(input))); + return Status::ok(); + } + + Status getFileDescriptor(unique_fd* output) { + *output = std::move(unique_fd(dup(mFd))); + return Status::ok(); + } + unique_fd mFd; }; std::vector<uint8_t> retrieveData(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); @@ -115,6 +131,7 @@ void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& tr // 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); + EXPECT_TRUE(seedData.size() != 0); // use fuzzService to replay the corpus FuzzedDataProvider provider(seedData.data(), seedData.size()); @@ -148,7 +165,14 @@ public: template <typename T, typename U> void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue, Status (IBinderRecordReplayTest::*get)(U*), U changedValue) { - auto replayFunctions = {&replayBinder, &replayFuzzService}; + using ReplayFunc = decltype(&replayFuzzService); + vector<ReplayFunc> replayFunctions = {&replayFuzzService}; + if (!std::is_same_v<U, unique_fd> && !std::is_same_v<U, sp<IBinder>>) { + // Parcel retrieved from record replay doesn't have object information. use it for + // replaying primitive types only. + replayFunctions.push_back(&replayBinder); + } + for (auto replayFunc : replayFunctions) { unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); @@ -156,7 +180,7 @@ public: // record a transaction mBpBinder->startRecordingBinder(fd); - auto status = (*mInterface.*set)(recordedValue); + auto status = (*mInterface.*set)(std::move(recordedValue)); EXPECT_TRUE(status.isOk()); mBpBinder->stopRecordingBinder(); @@ -164,16 +188,22 @@ public: U output; status = (*mInterface.*get)(&output); EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, recordedValue); + + // Expect this equal only if types are primitives + if (!std::is_same_v<U, unique_fd> && !std::is_same_v<U, sp<IBinder>>) { + EXPECT_EQ(output, recordedValue); + } // write over the existing state - status = (*mInterface.*set)(changedValue); + status = (*mInterface.*set)(std::move(changedValue)); EXPECT_TRUE(status.isOk()); status = (*mInterface.*get)(&output); EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, changedValue); + if (!std::is_same_v<U, unique_fd> && !std::is_same_v<U, sp<IBinder>>) { + EXPECT_EQ(output, changedValue); + } // replay transaction ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); @@ -186,7 +216,23 @@ public: status = (*mInterface.*get)(&output); EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, recordedValue); + + // FDs and binders will be replaced with random fd and random binders + if constexpr (std::is_same_v<U, unique_fd>) { + // verify that replayed fd is /dev/null. This is being replayed from random_fd.cpp + // and choosing /dav/null while generating seed in binder2corpus + std::string fdPath = "/proc/self/fd/" + std::to_string(output.get()); + char path[PATH_MAX]; + ASSERT_GT(readlink(fdPath.c_str(), path, sizeof(path)), 0); + EXPECT_EQ(strcmp("/dev/null", path), 0); + } else if constexpr (std::is_same_v<U, sp<IBinder>>) { + // This is binder is replayed from random_binder.cpp using seed data which writes + // this interface. + EXPECT_EQ(String16(kRandomInterfaceName.c_str(), kRandomInterfaceName.size()), + output->getInterfaceDescriptor()); + } else { + ASSERT_EQ(recordedValue, output); + } } } @@ -319,6 +365,32 @@ TEST_F(BinderRecordReplayTest, ReplaySingleDataParcelableArray) { &IBinderRecordReplayTest::getSingleDataParcelableArray, changed); } +TEST_F(BinderRecordReplayTest, ReplayBinder) { + vector<uint8_t> data = {0x8A, 0x19, 0x0D, 0x44, 0x37, 0x0D, 0x38, 0x5E, 0x9B, 0xAA, 0xF3, 0xDA}; + sp<IBinder> saved = new RandomBinder(String16("random_interface"), std::move(data)); + sp<IBinder> changed = IInterface::asBinder(defaultServiceManager()); + recordReplay(&IBinderRecordReplayTest::setBinder, saved, &IBinderRecordReplayTest::getBinder, + changed); +} + +TEST_F(BinderRecordReplayTest, ReplayFd) { + // Write something to both fds we are setting + unique_fd saved(open("/data/local/tmp/test_fd", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + std::string contentSaved = "This will be never read again for recorded fd!"; + CHECK(android::base::WriteFully(saved, contentSaved.data(), contentSaved.size())) + << saved.get(); + + unique_fd changed(open("/data/local/tmp/test_des", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + std::string contentChanged = "This will be never read again from changed fd!"; + CHECK(android::base::WriteFully(changed, contentChanged.data(), contentChanged.size())) + << changed.get(); + + // When fds are replayed, it will be replaced by /dev/null..reading from it should yield + // null data + recordReplay(&IBinderRecordReplayTest::setFileDescriptor, std::move(unique_fd(dup(saved))), + &IBinderRecordReplayTest::getFileDescriptor, std::move(unique_fd(dup(changed)))); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index 83db6c9b6d..fbab8f08a9 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -131,6 +131,13 @@ cc_library { "libcutils", "libutils", ], + static_libs: [ + "libbinder_random_parcel", + ], + include_dirs: [ + "bionic/libc/kernel/android/uapi/", + "bionic/libc/kernel/uapi/", + ], local_include_dirs: [ "include_random_parcel_seeds", ], @@ -140,8 +147,12 @@ cc_library { cc_binary_host { name: "binder2corpus", static_libs: [ + "libbinder_random_parcel", "libbinder_random_parcel_seeds", ], + cflags: [ + "-DBINDER_WITH_KERNEL_IPC", + ], srcs: [ "binder2corpus/binder2corpus.cpp", ], @@ -149,5 +160,6 @@ cc_binary_host { "libbase", "libbinder", "libutils", + "libcutils", ], } diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h index 8fc9263b98..7a1688b7b7 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h @@ -16,11 +16,25 @@ #pragma once +#include <binder/Binder.h> #include <binder/IBinder.h> #include <fuzzer/FuzzedDataProvider.h> namespace android { +class RandomBinder : public BBinder { +public: + RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes); + const String16& getInterfaceDescriptor() const override; + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; + +private: + String16 mDescriptor; + // note may not all be used + std::vector<uint8_t> mBytes; + FuzzedDataProvider mProvider; +}; + // Get a random binder object for use in fuzzing. // // May return nullptr. diff --git a/libs/binder/tests/parcel_fuzzer/random_binder.cpp b/libs/binder/tests/parcel_fuzzer/random_binder.cpp index 8a1fecb212..f41c35bfbe 100644 --- a/libs/binder/tests/parcel_fuzzer/random_binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_binder.cpp @@ -21,56 +21,52 @@ #include <binder/IInterface.h> #include <binder/IServiceManager.h> +size_t kRandomInterfaceLength = 50; namespace android { -class RandomBinder : public BBinder { -public: - RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes) - : mDescriptor(descriptor), - mBytes(std::move(bytes)), - mProvider(mBytes.data(), mBytes.size()) {} - const String16& getInterfaceDescriptor() const override { return mDescriptor; } +RandomBinder::RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes) + : mDescriptor(descriptor), + mBytes(std::move(bytes)), + mProvider(mBytes.data(), mBytes.size()) {} - status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override { - (void)code; - (void)data; - (void)reply; - (void)flags; // note - for maximum coverage even ignore if oneway +const String16& RandomBinder::getInterfaceDescriptor() const { + return mDescriptor; +} - if (mProvider.ConsumeBool()) { - return mProvider.ConsumeIntegral<status_t>(); - } +status_t RandomBinder::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + (void)code; + (void)data; + (void)reply; + (void)flags; // note - for maximum coverage even ignore if oneway - if (reply == nullptr) return OK; + if (mProvider.ConsumeBool()) { + return mProvider.ConsumeIntegral<status_t>(); + } - // TODO: things we could do to increase state space - // - also pull FDs and binders from 'data' - // (optionally combine these into random parcel 'options') - // - also pull FDs and binders from random parcel 'options' - RandomParcelOptions options; + if (reply == nullptr) return OK; - // random output - std::vector<uint8_t> subData = mProvider.ConsumeBytes<uint8_t>( - mProvider.ConsumeIntegralInRange<size_t>(0, mProvider.remaining_bytes())); - fillRandomParcel(reply, FuzzedDataProvider(subData.data(), subData.size()), &options); + // TODO: things we could do to increase state space + // - also pull FDs and binders from 'data' + // (optionally combine these into random parcel 'options') + // - also pull FDs and binders from random parcel 'options' + RandomParcelOptions options; - return OK; - } + // random output + std::vector<uint8_t> subData = mProvider.ConsumeBytes<uint8_t>( + mProvider.ConsumeIntegralInRange<size_t>(0, mProvider.remaining_bytes())); + fillRandomParcel(reply, FuzzedDataProvider(subData.data(), subData.size()), &options); -private: - String16 mDescriptor; - - // note may not all be used - std::vector<uint8_t> mBytes; - FuzzedDataProvider mProvider; -}; + return OK; +} sp<IBinder> getRandomBinder(FuzzedDataProvider* provider) { auto makeFunc = provider->PickValueInArray<const std::function<sp<IBinder>()>>({ [&]() { // descriptor is the length of a class name, e.g. // "some.package.Foo" - std::string str = provider->ConsumeRandomLengthString(100 /*max length*/); + std::string str = + provider->ConsumeRandomLengthString(kRandomInterfaceLength /*max length*/); // arbitrarily consume remaining data to create a binder that can return // random results - coverage guided fuzzer should ensure all of the remaining diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 4e58dc4899..62b84330cd 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -73,7 +73,7 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti return; } - if (options->extraFds.size() > 0 && provider.ConsumeBool()) { + if (provider.ConsumeBool() && options->extraFds.size() > 0) { const unique_fd& fd = options->extraFds.at( provider.ConsumeIntegralInRange<size_t>(0, options->extraFds.size() - @@ -102,7 +102,7 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti } sp<IBinder> binder; - if (options->extraBinders.size() > 0 && provider.ConsumeBool()) { + if (provider.ConsumeBool() && options->extraBinders.size() > 0) { binder = options->extraBinders.at( provider.ConsumeIntegralInRange<size_t>(0, options->extraBinders diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp index 7b3c80642b..fd9777a916 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -14,16 +14,26 @@ * limitations under the License. */ +#include <linux/android/binder.h> + #include <android-base/logging.h> +#include <binder/Parcel.h> #include <binder/RecordedTransaction.h> #include <fuzzseeds/random_parcel_seeds.h> +#include <stack> +#include <string> #include "../../file.h" using android::binder::borrowed_fd; using android::binder::WriteFully; +using std::stack; + +extern size_t kRandomInterfaceLength; +// Keep this in sync with max_length in random_binder.cpp while creating a RandomBinder +std::string kRandomInterfaceName(kRandomInterfaceLength, 'i'); namespace android { namespace impl { @@ -66,6 +76,162 @@ void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) { } // namespace impl +struct ProviderMetadata { + size_t position; + size_t value; + + ProviderMetadata() { + value = 0; + position = 0; + } +}; + +// Assuming current seed path is inside the fillRandomParcel function, start of the loop. +void writeRandomBinder(borrowed_fd fd, vector<uint8_t>& fillParcelBuffer, + stack<ProviderMetadata>& remainingPositions) { + // Choose 2 index in array + size_t fillFuncIndex = 2; + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2), + fillFuncIndex); + + // navigate to getRandomBinder. provide consume bool false + bool flag = false; + impl::writeReversedBuffer(fillParcelBuffer, flag); + + // selecting RandomBinder, other binders in the list are not recorded as KernelObjects + size_t randomBinderIndex = 0; + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2), + randomBinderIndex); + + // write random string of length 100 in actual buffer array. + CHECK(WriteFully(fd, kRandomInterfaceName.c_str(), kRandomInterfaceName.size())) << fd.get(); + + // These will be bytes which are used inside of RandomBinder + // simplest path for these bytes is going to be consume bool -> return random status + vector<uint8_t> randomBinderBuffer; + + bool returnRandomInt = true; + impl::writeReversedBuffer(randomBinderBuffer, returnRandomInt); + + status_t randomStatus = 0; + impl::writeReversedBuffer(randomBinderBuffer, randomStatus); + + // write integral in range to consume bytes for random binder + ProviderMetadata providerData; + providerData.position = fillParcelBuffer.size(); + providerData.value = randomBinderBuffer.size(); + remainingPositions.push(providerData); + + // Write to fd + CHECK(WriteFully(fd, randomBinderBuffer.data(), randomBinderBuffer.size())) << fd.get(); +} + +// Assuming current seed path is inside the fillRandomParcelFunction, start of the loop. +void writeRandomFd(vector<uint8_t>& fillParcelBuffer) { + // path to random fd + size_t fillFuncIndex = 1; + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2), + fillFuncIndex); + + bool flag = false; + impl::writeReversedBuffer(fillParcelBuffer, flag); + + // go for /dev/null index 1 + size_t fdIndex = 1; + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(3), + fdIndex); +} + +void writeParcelData(borrowed_fd fd, vector<uint8_t>& fillParcelBuffer, + stack<ProviderMetadata>& remainingPositions, const uint8_t* data, size_t start, + size_t length) { + // need to write parcel data till next offset with instructions to pick random bytes till offset + size_t fillFuncIndex = 0; + impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2), + fillFuncIndex); + + // provide how much bytes to read in control buffer + ProviderMetadata providerData; + providerData.position = fillParcelBuffer.size(); + providerData.value = length; + remainingPositions.push(providerData); + + // provide actual bytes + CHECK(WriteFully(fd, data + start, length)) << fd.get(); +} + +/** + * Generate sequence of copy data, write fd and write binder instructions and required data. + * Data which will be read using consumeBytes is written to fd directly. Data which is read in + * form integer is consumed from rear end FuzzedDataProvider. So insert it in fillParcelBuffer and + * then write to fd + */ +size_t regenerateParcel(borrowed_fd fd, vector<uint8_t>& fillParcelBuffer, const Parcel& p, + size_t dataSize, const vector<uint64_t>& objectOffsets) { + stack<ProviderMetadata> remainingPositions; + size_t copiedDataPosition = 0; + const uint8_t* parcelData = p.data(); + size_t numBinders = 0; + size_t numFds = 0; + + for (auto offset : objectOffsets) { + // Check what type of object is present here + const flat_binder_object* flatObject = + reinterpret_cast<const flat_binder_object*>(parcelData + offset); + // Copy till the object offset + writeParcelData(fd, fillParcelBuffer, remainingPositions, parcelData, copiedDataPosition, + offset - copiedDataPosition); + copiedDataPosition = offset; + if (flatObject->hdr.type == BINDER_TYPE_BINDER || + flatObject->hdr.type == BINDER_TYPE_HANDLE) { + writeRandomBinder(fd, fillParcelBuffer, remainingPositions); + numBinders++; + // In case of binder, stability is written after the binder object. + // We want to move the copiedDataPosition further to account for this stability field + copiedDataPosition += sizeof(int32_t) + sizeof(flat_binder_object); + } else if (flatObject->hdr.type == BINDER_TYPE_FD) { + writeRandomFd(fillParcelBuffer); + numFds++; + copiedDataPosition += sizeof(flat_binder_object); + } + } + + if (copiedDataPosition < dataSize) { + // copy remaining data from recorded parcel -> last Object to end of the data + writeParcelData(fd, fillParcelBuffer, remainingPositions, parcelData, copiedDataPosition, + dataSize - copiedDataPosition); + } + + // We need to write bytes for selecting integer within range of 0 to provide.remaining_bytes() + // is called. + size_t totalWrittenBytes = dataSize - (sizeof(flat_binder_object) * objectOffsets.size()) - + (sizeof(int32_t) * numBinders) + + (kRandomInterfaceName.size() /*Interface String*/ + sizeof(bool) + sizeof(status_t)) * + numBinders; + + // Code in fuzzService relies on provider.remaining_bytes() to select random bytes using + // consume integer. use the calculated remaining_bytes to generate byte buffer which can + // generate required fds and binders in fillRandomParcel function. + while (!remainingPositions.empty()) { + auto meta = remainingPositions.top(); + remainingPositions.pop(); + size_t remainingBytes = totalWrittenBytes + fillParcelBuffer.size() - meta.position; + + vector<uint8_t> remReversedBytes; + impl::writeReversedBuffer(remReversedBytes, static_cast<size_t>(0), remainingBytes, + meta.value); + // Check the order of buffer which is being written + fillParcelBuffer.insert(fillParcelBuffer.end() - meta.position, remReversedBytes.begin(), + remReversedBytes.end()); + } + + return totalWrittenBytes; +} + +/** + * Current corpus format + * |Reserved bytes(8)|parcel data|fillParcelBuffer|integralBuffer| + */ void generateSeedsFromRecording(borrowed_fd fd, const binder::debug::RecordedTransaction& transaction) { // Write Reserved bytes for future use @@ -123,17 +289,9 @@ void generateSeedsFromRecording(borrowed_fd fd, 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(); + auto objectMetadata = transaction.getObjectOffsets(); + size_t toWrite = regenerateParcel(fd, fillParcelBuffer, dataParcel, dataParcel.dataBufferSize(), + objectMetadata); // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data size_t subDataSize = toWrite + fillParcelBuffer.size(); diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp index 46fb068dee..a52f68ea32 100644 --- a/libs/gui/Choreographer.cpp +++ b/libs/gui/Choreographer.cpp @@ -116,7 +116,7 @@ Choreographer::~Choreographer() { std::lock_guard<std::mutex> _l(gChoreographers.lock); gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(), gChoreographers.ptrs.end(), - [=](Choreographer* c) { return c == this; }), + [=, this](Choreographer* c) { return c == this; }), gChoreographers.ptrs.end()); // Only poke DisplayManagerGlobal to unregister if we previously registered // callbacks. @@ -394,4 +394,4 @@ int64_t Choreographer::getStartTimeNanosForVsyncId(AVsyncId vsyncId) { return iter->second; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 462ce6e14f..15e8744713 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -3,6 +3,7 @@ // Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) // to integrate with auto-test framework. package { + default_team: "trendy_team_android_core_graphics_stack", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml index 31b10d7f54..b4ccf87349 100644 --- a/libs/gui/tests/AndroidTest.xml +++ b/libs/gui/tests/AndroidTest.xml @@ -18,6 +18,7 @@ <option name="cleanup" value="true" /> <option name="push" value="libgui_test->/data/local/tmp/libgui_test" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device --> <option name="screen-always-on" value="on" /> diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 022dfaddc1..a67ed29808 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -221,7 +221,7 @@ cc_library { "liblog", "libPlatformProperties", "libtinyxml2", - "libvintf", + "libz", // needed by libkernelconfigs ], ldflags: [ @@ -238,6 +238,7 @@ cc_library { "inputconstants-cpp", "libui-types", "libtflite_static", + "libkernelconfigs", ], whole_static_libs: [ diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 9c7c0c19ed..ccc83231fa 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -20,12 +20,14 @@ #include <unistd.h> #include <ctype.h> +#include <android-base/properties.h> #include <android-base/stringprintf.h> #include <ftl/enum.h> #include <gui/constants.h> #include <input/InputDevice.h> #include <input/InputEventLabels.h> +using android::base::GetProperty; using android::base::StringPrintf; namespace android { @@ -96,21 +98,22 @@ std::string getInputDeviceConfigurationFilePathByName( // Treblized input device config files will be located /product/usr, /system_ext/usr, // /odm/usr or /vendor/usr. - // These files may also be in the com.android.input.config APEX. - const char* rootsForPartition[]{ - "/product", - "/system_ext", - "/odm", - "/vendor", - "/apex/com.android.input.config/etc", - getenv("ANDROID_ROOT"), + std::vector<std::string> pathPrefixes{ + "/product/usr/", + "/system_ext/usr/", + "/odm/usr/", + "/vendor/usr/", }; - for (size_t i = 0; i < size(rootsForPartition); i++) { - if (rootsForPartition[i] == nullptr) { - continue; - } - path = rootsForPartition[i]; - path += "/usr/"; + // These files may also be in the APEX pointed by input_device.config_file.apex sysprop. + if (auto apex = GetProperty("input_device.config_file.apex", ""); !apex.empty()) { + pathPrefixes.push_back("/apex/" + apex + "/etc/usr/"); + } + // ANDROID_ROOT may not be set on host + if (auto android_root = getenv("ANDROID_ROOT"); android_root != nullptr) { + pathPrefixes.push_back(std::string(android_root) + "/usr/"); + } + for (const auto& prefix : pathPrefixes) { + path = prefix; appendInputDeviceConfigurationFileRelativePath(path, name, type); #if DEBUG_PROBE ALOGD("Probing for system provided input device configuration file: path='%s'", diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index 3c1ae3e41b..ab8c341b15 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -27,8 +27,7 @@ #include <utils/Timers.h> #include <utils/Tokenizer.h> #if defined(__ANDROID__) -#include <vintf/RuntimeInfo.h> -#include <vintf/VintfObject.h> +#include <vintf/KernelConfigs.h> #endif #include <cstdlib> @@ -98,12 +97,10 @@ static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_ bool kernelConfigsArePresent(const std::set<std::string>& configs) { #if defined(__ANDROID__) - std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo = - android::vintf::VintfObject::GetInstance()->getRuntimeInfo( - vintf::RuntimeInfo::FetchFlag::CONFIG_GZ); - LOG_ALWAYS_FATAL_IF(runtimeInfo == nullptr, "Kernel configs could not be fetched"); + std::map<std::string, std::string> kernelConfigs; + const status_t result = android::kernelconfigs::LoadKernelConfigs(&kernelConfigs); + LOG_ALWAYS_FATAL_IF(result != OK, "Kernel configs could not be fetched"); - const std::map<std::string, std::string>& kernelConfigs = runtimeInfo->kernelConfigs(); for (const std::string& requiredConfig : configs) { const auto configIt = kernelConfigs.find(requiredConfig); if (configIt == kernelConfigs.end()) { diff --git a/libs/input/input_verifier.rs b/libs/input/input_verifier.rs index f8dda3c901..767865ce12 100644 --- a/libs/input/input_verifier.rs +++ b/libs/input/input_verifier.rs @@ -184,7 +184,7 @@ impl InputVerifier { logger::init( logger::Config::default() .with_tag_on_device("InputVerifier") - .with_min_level(log::Level::Trace), + .with_max_level(log::LevelFilter::Trace), ); Self { name: name.to_owned(), touching_pointer_ids_by_device: HashMap::new() } } diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index e7224ff752..3fc7d9d568 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -36,8 +36,10 @@ cc_test { "libgmock", "libgui_window_info_static", "libinput", + "libkernelconfigs", "libtflite_static", "libui-types", + "libz", // needed by libkernelconfigs ], cflags: [ "-Wall", @@ -61,7 +63,6 @@ cc_test { "libPlatformProperties", "libtinyxml2", "libutils", - "libvintf", ], data: [ "data/*", diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index aab7df0c2c..22ad83463c 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,6 +16,8 @@ extern crate nativewindow_bindgen as ffi; +pub mod surface; + pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; use binder::{ @@ -210,7 +212,7 @@ impl Drop for HardwareBuffer { } impl Debug for HardwareBuffer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() } } diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs new file mode 100644 index 0000000000..25fea807b5 --- /dev/null +++ b/libs/nativewindow/rust/src/surface.rs @@ -0,0 +1,143 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Rust wrapper for `ANativeWindow` and related types. + +use binder::{ + binder_impl::{BorrowedParcel, UnstructuredParcelable}, + impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, + unstable_api::{status_result, AsNative}, + StatusCode, +}; +use nativewindow_bindgen::{ + AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat, + ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel, + ANativeWindow_release, ANativeWindow_writeToParcel, +}; +use std::error::Error; +use std::fmt::{self, Debug, Display, Formatter}; +use std::ptr::{null_mut, NonNull}; + +/// Wrapper around an opaque C `ANativeWindow`. +#[derive(PartialEq, Eq)] +pub struct Surface(NonNull<ANativeWindow>); + +impl Surface { + /// Returns the current width in pixels of the window surface. + pub fn width(&self) -> Result<u32, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) }; + width.try_into().map_err(|_| ErrorCode(width)) + } + + /// Returns the current height in pixels of the window surface. + pub fn height(&self) -> Result<u32, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) }; + height.try_into().map_err(|_| ErrorCode(height)) + } + + /// Returns the current pixel format of the window surface. + pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) }; + format.try_into().map_err(|_| ErrorCode(format)) + } +} + +impl Drop for Surface { + fn drop(&mut self) { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + unsafe { ANativeWindow_release(self.0.as_ptr()) } + } +} + +impl Debug for Surface { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Surface") + .field("width", &self.width()) + .field("height", &self.height()) + .field("format", &self.format()) + .finish() + } +} + +impl Clone for Surface { + fn clone(&self) -> Self { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + unsafe { ANativeWindow_acquire(self.0.as_ptr()) }; + Self(self.0) + } +} + +impl UnstructuredParcelable for Surface { + fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { + let status = + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) }; + status_result(status) + } + + fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { + let mut buffer = null_mut(); + + let status = + // SAFETY: Both pointers must be valid because they are obtained from references. + // `ANativeWindow_readFromParcel` doesn't store them or do anything else special + // with them. If it returns success then it will have allocated a new + // `ANativeWindow` and incremented the reference count, so we can use it until we + // release it. + unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) }; + + status_result(status)?; + + Ok(Self( + NonNull::new(buffer) + .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"), + )) + } +} + +impl_deserialize_for_unstructured_parcelable!(Surface); +impl_serialize_for_unstructured_parcelable!(Surface); + +// SAFETY: The underlying *ANativeWindow can be moved between threads. +unsafe impl Send for Surface {} + +// SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently. +unsafe impl Sync for Surface {} + +/// An error code returned by methods on [`Surface`]. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ErrorCode(i32); + +impl Error for ErrorCode {} + +impl Display for ErrorCode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "Error {}", self.0) + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h index 4525a42502..5689f7df94 100644 --- a/libs/nativewindow/rust/sys/nativewindow_bindings.h +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -19,3 +19,4 @@ #include <android/hardware_buffer_aidl.h> #include <android/hdr_metadata.h> #include <android/native_window.h> +#include <android/native_window_aidl.h> diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index d71e55f64c..a733fd0b8e 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -1022,7 +1022,7 @@ void SkiaRenderEngine::drawLayersInternal( .fakeOutputDataspace = fakeDataspace})); // Turn on dithering when dimming beyond this (arbitrary) threshold... - static constexpr float kDimmingThreshold = 0.2f; + static constexpr float kDimmingThreshold = 0.9f; // ...or we're rendering an HDR layer down to an 8-bit target // Most HDR standards require at least 10-bits of color depth for source content, so we // can just extract the transfer function rather than dig into precise gralloc layout. diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp index 16ed82af7c..82e5427317 100644 --- a/libs/ui/DisplayIdentification.cpp +++ b/libs/ui/DisplayIdentification.cpp @@ -21,6 +21,7 @@ #include <cctype> #include <numeric> #include <optional> +#include <span> #include <log/log.h> @@ -46,6 +47,7 @@ uint64_t shiftMix(uint64_t val) { return val ^ (val >> 47); } +__attribute__((no_sanitize("unsigned-integer-overflow"))) uint64_t hash64Len16(uint64_t u, uint64_t v) { constexpr uint64_t kMul = 0x9ddfea08eb382d69; uint64_t a = (u ^ v) * kMul; @@ -56,6 +58,7 @@ uint64_t hash64Len16(uint64_t u, uint64_t v) { return b; } +__attribute__((no_sanitize("unsigned-integer-overflow"))) uint64_t hash64Len0To16(const char* s, uint64_t len) { constexpr uint64_t k2 = 0x9ae16a3b2f90404f; constexpr uint64_t k3 = 0xc949d7c7509e6557; @@ -81,7 +84,7 @@ uint64_t hash64Len0To16(const char* s, uint64_t len) { return k2; } -using byte_view = std::basic_string_view<uint8_t>; +using byte_view = std::span<const uint8_t>; constexpr size_t kEdidBlockSize = 128; constexpr size_t kEdidHeaderLength = 5; @@ -89,7 +92,8 @@ constexpr size_t kEdidHeaderLength = 5; constexpr uint16_t kVirtualEdidManufacturerId = 0xffffu; std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) { - if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) { + if (static_cast<size_t>(view.size()) < kEdidHeaderLength || view[0] || view[1] || view[2] || + view[4]) { return {}; } @@ -164,7 +168,7 @@ Cea861ExtensionBlock parseCea861Block(const byte_view& block) { constexpr size_t kDataBlockHeaderSize = 1; const size_t dataBlockSize = bodyLength + kDataBlockHeaderSize; - if (block.size() < dataBlockOffset + dataBlockSize) { + if (static_cast<size_t>(block.size()) < dataBlockOffset + dataBlockSize) { ALOGW("Invalid EDID: CEA 861 data block is truncated."); break; } @@ -264,7 +268,7 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { } byte_view view(edid.data(), edid.size()); - view.remove_prefix(kDescriptorOffset); + view = view.subspan(kDescriptorOffset); std::string_view displayName; std::string_view serialNumber; @@ -274,13 +278,13 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { constexpr size_t kDescriptorLength = 18; for (size_t i = 0; i < kDescriptorCount; i++) { - if (view.size() < kDescriptorLength) { + if (static_cast<size_t>(view.size()) < kDescriptorLength) { break; } if (const auto type = getEdidDescriptorType(view)) { byte_view descriptor(view.data(), kDescriptorLength); - descriptor.remove_prefix(kEdidHeaderLength); + descriptor = descriptor.subspan(kEdidHeaderLength); switch (*type) { case 0xfc: @@ -295,7 +299,7 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { } } - view.remove_prefix(kDescriptorLength); + view = view.subspan(kDescriptorLength); } std::string_view modelString = displayName; @@ -327,8 +331,8 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { const size_t numExtensions = edid[kNumExtensionsOffset]; view = byte_view(edid.data(), edid.size()); for (size_t blockNumber = 1; blockNumber <= numExtensions; blockNumber++) { - view.remove_prefix(kEdidBlockSize); - if (view.size() < kEdidBlockSize) { + view = view.subspan(kEdidBlockSize); + if (static_cast<size_t>(view.size()) < kEdidBlockSize) { ALOGW("Invalid EDID: block %zu is truncated.", blockNumber); break; } @@ -399,4 +403,4 @@ uint64_t cityHash64Len0To16(std::string_view sv) { return hash64Len0To16(sv.data(), len); } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/ui/Gralloc5.cpp b/libs/ui/Gralloc5.cpp index c3b2d3d808..123bef4a4f 100644 --- a/libs/ui/Gralloc5.cpp +++ b/libs/ui/Gralloc5.cpp @@ -83,10 +83,18 @@ static void *loadIMapperLibrary() { return nullptr; } - std::string lib_name = "mapper." + mapperSuffix + ".so"; - void *so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW); + void* so = nullptr; + // TODO(b/322384429) switch this to __ANDROID_API_V__ when V is finalized + // TODO(b/302113279) use __ANDROID_VENDOR_API__ for vendor variant + if (__builtin_available(android __ANDROID_API_FUTURE__, *)) { + so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(), + RTLD_LOCAL | RTLD_NOW); + } else { + std::string lib_name = "mapper." + mapperSuffix + ".so"; + so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW); + } if (!so) { - ALOGE("Failed to load %s", lib_name.c_str()); + ALOGE("Failed to load mapper.%s.so", mapperSuffix.c_str()); } return so; }(); diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp index cb063af2f6..faa77ca9df 100644 --- a/libs/vibrator/fuzzer/Android.bp +++ b/libs/vibrator/fuzzer/Android.bp @@ -18,6 +18,7 @@ */ package { + default_team: "trendy_team_haptics_framework", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" diff --git a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h index 2d0a4ea6ec..371ed89fc9 100644 --- a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h +++ b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h @@ -17,12 +17,12 @@ namespace rpc { // C strings more efficient by avoiding unnecessary copies when remote method // signatures specify std::basic_string arguments or return values. template <typename CharT = std::string::value_type, - typename Traits = std::char_traits<CharT>> + typename Traits = std::char_traits<std::remove_cv_t<CharT>>> class StringWrapper { public: // Define types in the style of STL strings to support STL operators. typedef Traits traits_type; - typedef typename Traits::char_type value_type; + typedef CharT value_type; typedef std::size_t size_type; typedef value_type& reference; typedef const value_type& const_reference; diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen index 7fd9c3a735..f73fa5d63c 100755 --- a/opengl/tools/glgen/gen +++ b/opengl/tools/glgen/gen @@ -22,8 +22,10 @@ mkdir out mkdir -p out/javax/microedition/khronos/opengles mkdir -p out/com/google/android/gles_jni +mkdir -p out/android/annotation mkdir -p out/android/app mkdir -p out/android/graphics +mkdir -p out/android/hardware mkdir -p out/android/view mkdir -p out/android/opengl mkdir -p out/android/content @@ -34,18 +36,20 @@ mkdir -p out/android/util echo "package android.graphics;" > out/android/graphics/Canvas.java echo "public interface Canvas {}" >> out/android/graphics/Canvas.java +echo "package android.annotation; public @interface NonNull {}" > out/android/annotation/NonNull.java echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java # echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags, java.lang.String userId) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java -echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;}; }" > out/android/os/Build.java +echo "package android.hardware; import android.os.ParcelFileDescriptor; public class SyncFence { public static SyncFence create(ParcelFileDescriptor w) { return null; } public static SyncFence createEmpty() { return null; } }" > out/android/hardware/SyncFence.java +echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 0; public static final int R = 0; }; }" > out/android/os/Build.java +echo "package android.os; public class ParcelFileDescriptor { public static ParcelFileDescriptor adoptFd(int fd) { return null; } }" > out/android/os/ParcelFileDescriptor.java echo "package android.os; public class UserHandle {public static String myUserId() { return \"\"; } }" > out/android/os/UserHandle.java echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java -echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java +echo "package android.util; public class Log {public static void d(String a, String b) {} public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java - echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java echo "package android.view;" > out/android/view/SurfaceView.java diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if index 951ecffc32..695b571a92 100644 --- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if +++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if @@ -20,6 +20,7 @@ package android.opengl; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; +import android.os.Build; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp index b2ea041cd5..ea55179bbd 100644 --- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp +++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp index 6dffac5945..8e452fb9cd 100644 --- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp +++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" diff --git a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if index 523bc574be..75e17044c6 100644 --- a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if +++ b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if @@ -18,6 +18,11 @@ package android.opengl; +import android.annotation.NonNull; +import android.hardware.SyncFence; +import android.os.ParcelFileDescriptor; +import android.util.Log; + /** * EGL Extensions */ @@ -30,8 +35,44 @@ public class EGLExt { public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; public static final int EGL_RECORDABLE_ANDROID = 0x3142; + // EGL_ANDROID_native_fence_sync + public static final int EGL_SYNC_NATIVE_FENCE_ANDROID = 0x3144; + public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID = 0x3145; + public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 0x3146; + public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID = -1; + native private static void _nativeClassInit(); static { _nativeClassInit(); } + /** + * Retrieves the SyncFence for an EGLSync created with EGL_SYNC_NATIVE_FENCE_ANDROID + * + * See <a href="https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt"> + * EGL_ANDROID_native_fence_sync</a> extension for more details + * @param display The EGLDisplay connection + * @param sync The EGLSync to fetch the SyncFence from + * @return A SyncFence representing the native fence. + * * If <sync> is not a valid sync object for <display>, + * an {@link SyncFence#isValid() invalid} SyncFence is returned and an EGL_BAD_PARAMETER + * error is generated. + * * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is + * EGL_NO_NATIVE_FENCE_FD_ANDROID, an {@link SyncFence#isValid() invalid} SyncFence is + * returned and an EGL_BAD_PARAMETER error is generated. + * * If <display> does not match the display passed to eglCreateSync + * when <sync> was created, the behaviour is undefined. + */ + public static @NonNull SyncFence eglDupNativeFenceFDANDROID(@NonNull EGLDisplay display, + @NonNull EGLSync sync) { + int fd = eglDupNativeFenceFDANDROIDImpl(display, sync); + Log.d("EGL", "eglDupNativeFence returned " + fd); + if (fd >= 0) { + return SyncFence.create(ParcelFileDescriptor.adoptFd(fd)); + } else { + return SyncFence.createEmpty(); + } + } + + private static native int eglDupNativeFenceFDANDROIDImpl(EGLDisplay display, EGLSync sync); + diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp index be8b3e3977..f1f0ac574b 100644 --- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" @@ -37,25 +38,12 @@ #include <ui/ANativeObjectBase.h> static jclass egldisplayClass; -static jclass eglcontextClass; static jclass eglsurfaceClass; -static jclass eglconfigClass; +static jclass eglsyncClass; static jmethodID egldisplayGetHandleID; -static jmethodID eglcontextGetHandleID; static jmethodID eglsurfaceGetHandleID; -static jmethodID eglconfigGetHandleID; - -static jmethodID egldisplayConstructor; -static jmethodID eglcontextConstructor; -static jmethodID eglsurfaceConstructor; -static jmethodID eglconfigConstructor; - -static jobject eglNoContextObject; -static jobject eglNoDisplayObject; -static jobject eglNoSurfaceObject; - - +static jmethodID eglsyncGetHandleID; /* Cache method IDs each time the class is loaded. */ @@ -64,37 +52,14 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) { jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay"); egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal); - jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext"); - eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal); jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface"); eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal); - jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig"); - eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal); + jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync"); + eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal); egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J"); - eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J"); eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J"); - eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J"); - - - egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V"); - eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V"); - eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V"); - eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V"); - - - jclass eglClass = _env->FindClass("android/opengl/EGL14"); - jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;"); - jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID); - eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject); - - jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;"); - jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID); - eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject); - - jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;"); - jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID); - eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject); + eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J"); } static void * @@ -108,24 +73,12 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) { return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid)); } -static jobject -toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) { - if (cls == eglcontextClass && - (EGLContext)handle == EGL_NO_CONTEXT) { - return eglNoContextObject; - } - - if (cls == egldisplayClass && - (EGLDisplay)handle == EGL_NO_DISPLAY) { - return eglNoDisplayObject; - } - - if (cls == eglsurfaceClass && - (EGLSurface)handle == EGL_NO_SURFACE) { - return eglNoSurfaceObject; - } +// TODO: this should be generated from the .spec file, but needs to be renamed and made private +static jint android_eglDupNativeFenceFDANDROID(JNIEnv *env, jobject, jobject dpy, jobject sync) { + EGLDisplay dpy_native = (EGLDisplay)fromEGLHandle(env, egldisplayGetHandleID, dpy); + EGLSync sync_native = (EGLSync)fromEGLHandle(env, eglsyncGetHandleID, sync); - return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle)); + return eglDupNativeFenceFDANDROID(dpy_native, sync_native); } // -------------------------------------------------------------------------- diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java index 85f743d815..78b0819374 100755 --- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java +++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java @@ -7,7 +7,7 @@ /** * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static native EGLDisplay eglGetDisplay( long display_id ); diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp index dd17ca458a..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp @@ -18,6 +18,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES/gl.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp index dd17ca458a..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp @@ -18,6 +18,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES/gl.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp index dd17ca458a..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp @@ -18,6 +18,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES/gl.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp index dd17ca458a..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp @@ -18,6 +18,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES/gl.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp index b2bbdf6fe9..4004a7dfcf 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp @@ -18,6 +18,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES2/gl2.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp index b039bc9a83..c5bdf323fc 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp @@ -18,6 +18,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES3/gl3.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp index dd00e9205c..2260a80bb4 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <GLES3/gl31.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp index 88e00bef6e..130612d7cc 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <stdint.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp index 3e7ec8b2de..5446fc2fc3 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES32cHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include <stdint.h> diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index 9cab1d6a59..c3534bff31 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -17,6 +17,7 @@ // This source file is automatically generated #pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-function" #include "jni.h" diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index 4e2a6fbf87..e5d2b705c3 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -1,4 +1,5 @@ package { + default_team: "trendy_team_input_framework", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 1585fddfb3..a5564d2c7d 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_input_framework", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp index 47b0824fd0..59af4934fa 100644 --- a/services/inputflinger/tests/fuzzers/Android.bp +++ b/services/inputflinger/tests/fuzzers/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_input_framework", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index c0eb36dc02..3cda3343b0 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -325,7 +325,9 @@ void AidlComposer::registerCallback(HWC2::ComposerCallback& callback) { } mAidlComposerCallback = ndk::SharedRefBase::make<AidlIComposerCallbackWrapper>(callback); - AIBinder_setMinSchedulerPolicy(mAidlComposerCallback->asBinder().get(), SCHED_FIFO, 2); + + ndk::SpAIBinder binder = mAidlComposerCallback->asBinder(); + AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_FIFO, 2); const auto status = mAidlComposerClient->registerCallback(mAidlComposerCallback); if (!status.isOk()) { diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp index a468146bc0..5437995899 100644 --- a/services/vibratorservice/benchmarks/Android.bp +++ b/services/vibratorservice/benchmarks/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_haptics_framework", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp index 32947246d8..be71dc2ce3 100644 --- a/services/vibratorservice/test/Android.bp +++ b/services/vibratorservice/test/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_haptics_framework", // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "frameworks_native_license" |