diff options
| -rw-r--r-- | cmds/dumpstate/dumpstate.cpp | 15 | ||||
| -rw-r--r-- | cmds/dumpsys/dumpsys.cpp | 35 | ||||
| -rw-r--r-- | cmds/dumpsys/main.cpp | 5 | ||||
| -rw-r--r-- | libs/binder/Android.bp | 1 | ||||
| -rw-r--r-- | libs/binder/IPCThreadState.cpp | 5 | ||||
| -rw-r--r-- | libs/binder/ndk/ibinder.cpp | 49 | ||||
| -rw-r--r-- | libs/binder/ndk/ibinder_internal.h | 2 | ||||
| -rw-r--r-- | libs/binder/ndk/include_ndk/android/binder_interface_utils.h | 43 | ||||
| -rw-r--r-- | libs/binder/ndk/include_platform/android/binder_shell.h | 55 | ||||
| -rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 1 | ||||
| -rw-r--r-- | libs/binder/ndk/test/Android.bp | 1 | ||||
| -rw-r--r-- | libs/binder/ndk/test/libbinder_ndk_unit_test.cpp | 100 | ||||
| -rw-r--r-- | libs/gralloc/types/Gralloc4.cpp | 65 | ||||
| -rw-r--r-- | libs/gralloc/types/fuzzer/gralloctypes.cpp | 1 | ||||
| -rw-r--r-- | libs/gralloc/types/include/gralloctypes/Gralloc4.h | 28 | ||||
| -rw-r--r-- | libs/gralloc/types/tests/Gralloc4_test.cpp | 36 | ||||
| -rw-r--r-- | services/surfaceflinger/TimeStats/TimeStats.cpp | 3 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/SurfaceFlinger_test.filter | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/TimeStatsTest.cpp | 13 |
19 files changed, 404 insertions, 56 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 311ddc4b51..8e0f8a35d6 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -154,6 +154,7 @@ void add_mountinfo(); #define RECOVERY_DATA_DIR "/data/misc/recovery" #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log" #define LOGPERSIST_DATA_DIR "/data/misc/logd" +#define PREREBOOT_DATA_DIR "/data/misc/prereboot" #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur" #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref" #define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat" @@ -1438,11 +1439,14 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); /* Binder state is expensive to look at as it uses a lot of memory. */ - DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); - DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); - DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions"); - DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats"); - DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state"); + std::string binder_logs_dir = access("/dev/binderfs/binder_logs", R_OK) ? + "/sys/kernel/debug/binder" : "/dev/binderfs/binder_logs"; + + DumpFile("BINDER FAILED TRANSACTION LOG", binder_logs_dir + "/failed_transaction_log"); + DumpFile("BINDER TRANSACTION LOG", binder_logs_dir + "/transaction_log"); + DumpFile("BINDER TRANSACTIONS", binder_logs_dir + "/transactions"); + DumpFile("BINDER STATS", binder_logs_dir + "/stats"); + DumpFile("BINDER STATE", binder_logs_dir + "/state"); /* Add window and surface trace files. */ if (!PropertiesHelper::IsUserBuild()) { @@ -1582,6 +1586,7 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { ds.AddDir(PROFILE_DATA_DIR_CUR, true); ds.AddDir(PROFILE_DATA_DIR_REF, true); } + ds.AddDir(PREREBOOT_DATA_DIR, false); add_mountinfo(); DumpIpTablesAsRoot(); DumpDynamicPartitionInfo(); diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index 5597bcd915..a427c8dd68 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -29,6 +29,7 @@ #include <utils/Log.h> #include <utils/Vector.h> +#include <iostream> #include <fcntl.h> #include <getopt.h> #include <stdio.h> @@ -231,14 +232,14 @@ int Dumpsys::main(int argc, char* const argv[]) { const size_t N = services.size(); if (N > 1) { // first print a list of the current services - aout << "Currently running services:" << endl; + std::cout << "Currently running services:" << std::endl; for (size_t i=0; i<N; i++) { sp<IBinder> service = sm_->checkService(services[i]); if (service != nullptr) { bool skipped = IsSkipped(skippedServices, services[i]); - aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl; + std::cout << " " << services[i] << (skipped ? " (skipped)" : "") << std::endl; } } } @@ -263,10 +264,10 @@ int Dumpsys::main(int argc, char* const argv[]) { asProto, elapsedDuration, bytesWritten); if (status == TIMED_OUT) { - aout << endl + std::cout << std::endl << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs - << "ms) EXPIRED ***" << endl - << endl; + << "ms) EXPIRED ***" << std::endl + << std::endl; } if (addSeparator) { @@ -332,14 +333,14 @@ status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, const Vector<String16>& args) { sp<IBinder> service = sm_->checkService(serviceName); if (service == nullptr) { - aerr << "Can't find service: " << serviceName << endl; + std::cerr << "Can't find service: " << serviceName << std::endl; return NAME_NOT_FOUND; } int sfd[2]; if (pipe(sfd) != 0) { - aerr << "Failed to create pipe to dump service info for " << serviceName << ": " - << strerror(errno) << endl; + std::cerr << "Failed to create pipe to dump service info for " << serviceName << ": " + << strerror(errno) << std::endl; return -errno; } @@ -359,13 +360,13 @@ status_t Dumpsys::startDumpThread(Type type, const String16& serviceName, err = dumpPidToFd(service, remote_end); break; default: - aerr << "Unknown dump type" << static_cast<int>(type) << endl; + std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl; return; } if (err != OK) { - aerr << "Error dumping service info status_t: " << statusToString(err) << " " - << serviceName << endl; + std::cerr << "Error dumping service info status_t: " << statusToString(err) << " " + << serviceName << std::endl; } }); return OK; @@ -422,8 +423,8 @@ status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::mi int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms())); if (rc < 0) { - aerr << "Error in poll while dumping service " << serviceName << " : " - << strerror(errno) << endl; + std::cerr << "Error in poll while dumping service " << serviceName << " : " + << strerror(errno) << std::endl; status = -errno; break; } else if (rc == 0) { @@ -434,8 +435,8 @@ status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::mi char buf[4096]; rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf))); if (rc < 0) { - aerr << "Failed to read while dumping service " << serviceName << ": " - << strerror(errno) << endl; + std::cerr << "Failed to read while dumping service " << serviceName << ": " + << strerror(errno) << std::endl; status = -errno; break; } else if (rc == 0) { @@ -444,8 +445,8 @@ status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::mi } if (!WriteFully(fd, buf, rc)) { - aerr << "Failed to write while dumping service " << serviceName << ": " - << strerror(errno) << endl; + std::cerr << "Failed to write while dumping service " << serviceName << ": " + << strerror(errno) << std::endl; status = -errno; break; } diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp index 8ba0eba0fa..fa4cc97b91 100644 --- a/cmds/dumpsys/main.cpp +++ b/cmds/dumpsys/main.cpp @@ -21,10 +21,9 @@ #include "dumpsys.h" #include <binder/IServiceManager.h> -#include <binder/TextOutput.h> +#include <iostream> #include <signal.h> -#include <stdio.h> using namespace android; @@ -34,7 +33,7 @@ int main(int argc, char* const argv[]) { fflush(stdout); if (sm == nullptr) { ALOGE("Unable to get default service manager!"); - aerr << "dumpsys: Unable to get default service manager!" << endl; + std::cerr << "dumpsys: Unable to get default service manager!" << std::endl; return 20; } diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 5f9d4004f4..bc541f4d31 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -170,7 +170,6 @@ aidl_interface { name: "libbinder_aidl_test_stub", local_include_dir: "aidl", srcs: [":libbinder_aidl"], - visibility: [":__subpackages__"], vendor_available: true, backend: { java: { diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 4dcd07a776..9e89c57da3 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1230,6 +1230,11 @@ status_t IPCThreadState::executeCommand(int32_t cmd) if (error < NO_ERROR) reply.setError(error); sendReply(reply, 0); } else { + if (error != OK || reply.dataSize() != 0) { + alog << "oneway function results will be dropped but finished with status " + << statusToString(error) + << " and parcel size " << reply.dataSize() << endl; + } LOG_ONEWAY("NOT sending reply to %d!", mCallingPid); } diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index e752c45d60..75dcdc8389 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -24,10 +24,13 @@ #include <android-base/logging.h> #include <binder/IPCThreadState.h> +#include <binder/IResultReceiver.h> +#include <private/android_filesystem_config.h> using DeathRecipient = ::android::IBinder::DeathRecipient; using ::android::IBinder; +using ::android::IResultReceiver; using ::android::Parcel; using ::android::sp; using ::android::status_t; @@ -158,6 +161,45 @@ status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parce binder_status_t status = getClass()->onTransact(this, code, &in, &out); return PruneStatusT(status); + } else if (code == SHELL_COMMAND_TRANSACTION) { + int in = data.readFileDescriptor(); + int out = data.readFileDescriptor(); + int err = data.readFileDescriptor(); + + int argc = data.readInt32(); + std::vector<String8> utf8Args; // owns memory of utf8s + std::vector<const char*> utf8Pointers; // what can be passed over NDK API + for (int i = 0; i < argc && data.dataAvail() > 0; i++) { + utf8Args.push_back(String8(data.readString16())); + utf8Pointers.push_back(utf8Args[i].c_str()); + } + + data.readStrongBinder(); // skip over the IShellCallback + sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(data.readStrongBinder()); + + // Shell commands should only be callable by ADB. + uid_t uid = AIBinder_getCallingUid(); + if (uid != AID_ROOT && uid != AID_SHELL) { + if (resultReceiver != nullptr) { + resultReceiver->send(-1); + } + return STATUS_PERMISSION_DENIED; + } + + // Check that the file descriptors are valid. + if (in == STATUS_BAD_TYPE || out == STATUS_BAD_TYPE || err == STATUS_BAD_TYPE) { + if (resultReceiver != nullptr) { + resultReceiver->send(-1); + } + return STATUS_BAD_VALUE; + } + + binder_status_t status = getClass()->handleShellCommand( + this, in, out, err, utf8Pointers.data(), utf8Pointers.size()); + if (resultReceiver != nullptr) { + resultReceiver->send(status); + } + return status; } else { return BBinder::onTransact(code, data, reply, flags); } @@ -266,6 +308,13 @@ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) { clazz->onDump = onDump; } +void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz, + AIBinder_handleShellCommand handleShellCommand) { + CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz"; + + clazz->handleShellCommand = handleShellCommand; +} + void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) { CHECK(who == mWho); diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index 5cb68c291b..57794279f2 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -17,6 +17,7 @@ #pragma once #include <android/binder_ibinder.h> +#include <android/binder_shell.h> #include "ibinder_internal.h" #include <atomic> @@ -115,6 +116,7 @@ struct AIBinder_Class { // optional methods for a class AIBinder_onDump onDump; + AIBinder_handleShellCommand handleShellCommand; private: // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h index 83a10488e0..7331ba20c4 100644 --- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h @@ -30,6 +30,11 @@ #include <android/binder_auto_utils.h> #include <android/binder_ibinder.h> +#if __has_include(<android/binder_shell.h>) +#include <android/binder_shell.h> +#define HAS_BINDER_SHELL_COMMAND +#endif //_has_include + #include <assert.h> #include <memory> @@ -108,7 +113,15 @@ class ICInterface : public SharedRefBase { /** * Dumps information about the interface. By default, dumps nothing. */ - virtual inline binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/); + virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs); + +#ifdef HAS_BINDER_SHELL_COMMAND + /** + * Process shell commands. By default, does nothing. + */ + virtual inline binder_status_t handleShellCommand(int in, int out, int err, const char** argv, + uint32_t argc); +#endif /** * Interprets this binder as this underlying interface if this has stored an ICInterface in the @@ -136,6 +149,11 @@ class ICInterface : public SharedRefBase { static inline void onDestroy(void* userData); static inline binder_status_t onDump(AIBinder* binder, int fd, const char** args, uint32_t numArgs); + +#ifdef HAS_BINDER_SHELL_COMMAND + static inline binder_status_t handleShellCommand(AIBinder* binder, int in, int out, int err, + const char** argv, uint32_t argc); +#endif }; }; @@ -191,6 +209,13 @@ binder_status_t ICInterface::dump(int /*fd*/, const char** /*args*/, uint32_t /* return STATUS_OK; } +#ifdef HAS_BINDER_SHELL_COMMAND +binder_status_t ICInterface::handleShellCommand(int /*in*/, int /*out*/, int /*err*/, + const char** /*argv*/, uint32_t /*argc*/) { + return STATUS_OK; +} +#endif + std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) { return ICInterfaceData::getInterface(binder); } @@ -203,9 +228,12 @@ AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, return nullptr; } - // We can't know if this method is overriden by a subclass interface, so we must register - // ourselves. The default (nothing to dump) is harmless. + // We can't know if these methods are overridden by a subclass interface, so we must register + // ourselves. The defaults are harmless. AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump); +#ifdef HAS_BINDER_SHELL_COMMAND + AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand); +#endif return clazz; } @@ -234,6 +262,15 @@ binder_status_t ICInterface::ICInterfaceData::onDump(AIBinder* binder, int fd, c return interface->dump(fd, args, numArgs); } +#ifdef HAS_BINDER_SHELL_COMMAND +binder_status_t ICInterface::ICInterfaceData::handleShellCommand(AIBinder* binder, int in, int out, + int err, const char** argv, + uint32_t argc) { + std::shared_ptr<ICInterface> interface = getInterface(binder); + return interface->handleShellCommand(in, out, err, argv, argc); +} +#endif + template <typename INTERFACE> SpAIBinder BnCInterface<INTERFACE>::asBinder() { std::lock_guard<std::mutex> l(mMutex); diff --git a/libs/binder/ndk/include_platform/android/binder_shell.h b/libs/binder/ndk/include_platform/android/binder_shell.h new file mode 100644 index 0000000000..17b38b0dae --- /dev/null +++ b/libs/binder/ndk/include_platform/android/binder_shell.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/binder_ibinder.h> + +__BEGIN_DECLS + +/** + * Function to execute a shell command. + * + * Available since API level 30. + * + * \param binder the binder executing the command + * \param in input file descriptor, should be flushed, ownership is not passed + * \param out output file descriptor, should be flushed, ownership is not passed + * \param err error file descriptor, should be flushed, ownership is not passed + * \param argv array of null-terminated strings for command (may be null if argc + * is 0) + * \param argc length of argv array + * + * \return binder_status_t result of transaction + */ +typedef binder_status_t (*AIBinder_handleShellCommand)(AIBinder* binder, int in, int out, int err, + const char** argv, uint32_t argc); + +/** + * This sets the implementation of handleShellCommand for a class. + * + * If this isn't set, nothing will be executed when handleShellCommand is called. + * + * Available since API level 30. + * + * \param handleShellCommand function to call when a shell transaction is + * received + */ +void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz, + AIBinder_handleShellCommand handleShellCommand) + __INTRODUCED_IN(30); + +__END_DECLS diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index f3158d7e18..7e72f22d64 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -110,6 +110,7 @@ LIBBINDER_NDK30 { # introduced=30 AIBinder_markSystemStability; # apex AIBinder_markVendorStability; # llndk AIBinder_markVintfStability; # apex llndk + AIBinder_Class_setHandleShellCommand; # apex llndk local: *; }; diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index 513d8c2eba..cb4b20ff9d 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -60,6 +60,7 @@ cc_test { defaults: ["test_libbinder_ndk_test_defaults"], srcs: ["libbinder_ndk_unit_test.cpp"], static_libs: [ + "IBinderNdkUnitTest-cpp", "IBinderNdkUnitTest-ndk_platform", ], test_suites: ["general-tests"], diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp index 51dd169ec0..fd30d87c76 100644 --- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <IBinderNdkUnitTest.h> #include <aidl/BnBinderNdkUnitTest.h> #include <aidl/BnEmpty.h> #include <android-base/logging.h> @@ -26,13 +27,16 @@ // warning: this is assuming that libbinder_ndk is using the same copy // of libbinder that we are. #include <binder/IPCThreadState.h> +#include <binder/IResultReceiver.h> +#include <binder/IServiceManager.h> +#include <binder/IShellCallback.h> #include <sys/prctl.h> #include <chrono> #include <condition_variable> #include <mutex> -using ::android::sp; +using namespace android; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; @@ -48,6 +52,14 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { android::IPCThreadState::self()->flushCommands(); return ndk::ScopedAStatus::ok(); } + binder_status_t handleShellCommand(int /*in*/, int out, int /*err*/, const char** args, + uint32_t numArgs) override { + for (uint32_t i = 0; i < numArgs; i++) { + dprintf(out, "%s", args[i]); + } + fsync(out); + return STATUS_OK; + } }; int generatedService() { @@ -296,6 +308,92 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { EXPECT_TRUE(destroyed); } +class MyResultReceiver : public BnResultReceiver { + public: + Mutex mMutex; + Condition mCondition; + bool mHaveResult = false; + int32_t mResult = 0; + + virtual void send(int32_t resultCode) { + AutoMutex _l(mMutex); + mResult = resultCode; + mHaveResult = true; + mCondition.signal(); + } + + int32_t waitForResult() { + AutoMutex _l(mMutex); + while (!mHaveResult) { + mCondition.wait(mMutex); + } + return mResult; + } +}; + +class MyShellCallback : public BnShellCallback { + public: + virtual int openFile(const String16& /*path*/, const String16& /*seLinuxContext*/, + const String16& /*mode*/) { + // Empty implementation. + return 0; + } +}; + +bool ReadFdToString(int fd, std::string* content) { + char buf[64]; + ssize_t n; + while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) { + content->append(buf, n); + } + return (n == 0) ? true : false; +} + +std::string shellCmdToString(sp<IBinder> unitTestService, const std::vector<const char*>& args) { + int inFd[2] = {-1, -1}; + int outFd[2] = {-1, -1}; + int errFd[2] = {-1, -1}; + + EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, inFd)); + EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, outFd)); + EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, errFd)); + + sp<MyShellCallback> cb = new MyShellCallback(); + sp<MyResultReceiver> resultReceiver = new MyResultReceiver(); + + Vector<String16> argsVec; + for (int i = 0; i < args.size(); i++) { + argsVec.add(String16(args[i])); + } + status_t error = IBinder::shellCommand(unitTestService, inFd[0], outFd[0], errFd[0], argsVec, + cb, resultReceiver); + EXPECT_EQ(error, android::OK); + + status_t res = resultReceiver->waitForResult(); + EXPECT_EQ(res, android::OK); + + close(inFd[0]); + close(inFd[1]); + close(outFd[0]); + close(errFd[0]); + close(errFd[1]); + + std::string ret; + EXPECT_TRUE(ReadFdToString(outFd[1], &ret)); + close(outFd[1]); + return ret; +} + +TEST(NdkBinder, UseHandleShellCommand) { + static const sp<android::IServiceManager> sm(android::defaultServiceManager()); + sp<IBinder> testService = sm->getService(String16(kBinderNdkUnitTestService)); + + EXPECT_EQ("", shellCmdToString(testService, {})); + EXPECT_EQ("", shellCmdToString(testService, {"", ""})); + EXPECT_EQ("Hello world!", shellCmdToString(testService, {"Hello ", "world!"})); + EXPECT_EQ("CMD", shellCmdToString(testService, {"C", "M", "D"})); +} + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index 4e8569f2de..603e7e559f 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -734,12 +734,7 @@ status_t encodePlaneLayout(const PlaneLayout& input, OutputHidlVec* output) { if (err) { return err; } - err = encodeInteger<int64_t>(static_cast<int32_t>(input.verticalSubsampling), output); - if (err) { - return err; - } - - return encodeRect(input.crop, output); + return encodeInteger<int64_t>(static_cast<int32_t>(input.verticalSubsampling), output); } status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) { @@ -780,12 +775,7 @@ status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) { if (err) { return err; } - err = decodeInteger<int64_t>(input, &output->verticalSubsampling); - if (err) { - return err; - } - - return decodeRect(input, &output->crop); + return decodeInteger<int64_t>(input, &output->verticalSubsampling); } status_t encodePlaneLayoutsHelper(const std::vector<PlaneLayout>& planeLayouts, OutputHidlVec* outOutputHidlVec) { @@ -831,6 +821,49 @@ void clearPlaneLayouts(std::vector<PlaneLayout>* output) { output->clear(); } +status_t encodeCropHelper(const std::vector<Rect>& crops, OutputHidlVec* outOutputHidlVec) { + status_t err = encodeInteger<int64_t>(static_cast<int64_t>(crops.size()), outOutputHidlVec); + if (err) { + return err; + } + + for (const auto& crop : crops) { + err = encodeRect(crop, outOutputHidlVec); + if (err) { + return err; + } + } + + return NO_ERROR; +} + +status_t decodeCropHelper(InputHidlVec* inputHidlVec, std::vector<Rect>* outCrops) { + int64_t size = 0; + status_t err = decodeInteger<int64_t>(inputHidlVec, &size); + if (err) { + return err; + } + if (size < 0) { + return BAD_VALUE; + } + + for (size_t i = 0; i < size; i++) { + outCrops->emplace_back(); + err = decodeRect(inputHidlVec, &outCrops->back()); + if (err) { + return err; + } + } + return NO_ERROR; +} + +void clearCrop(std::vector<Rect>* output) { + if (!output) { + return; + } + output->clear(); +} + status_t encodeSmpte2086Helper(const Smpte2086& smpte2086, OutputHidlVec* outOutputHidlVec) { status_t err = encodeXyColor(smpte2086.primaryRed, outOutputHidlVec); if (err) { @@ -1043,6 +1076,14 @@ status_t decodePlaneLayouts(const hidl_vec<uint8_t>& planeLayouts, std::vector<P decodePlaneLayoutsHelper, clearPlaneLayouts); } +status_t encodeCrop(const std::vector<Rect>& crop, hidl_vec<uint8_t>* outCrop) { + return encodeMetadata(MetadataType_Crop, crop, outCrop, encodeCropHelper); +} + +status_t decodeCrop(const hidl_vec<uint8_t>& crop, std::vector<Rect>* outCrop) { + return decodeMetadata(MetadataType_Crop, crop, outCrop, decodeCropHelper, clearCrop); +} + status_t encodeDataspace(const Dataspace& dataspace, hidl_vec<uint8_t>* outDataspace) { return encodeMetadata(MetadataType_Dataspace, static_cast<int32_t>(dataspace), outDataspace, encodeInteger); diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp index b5644beafb..dc22385883 100644 --- a/libs/gralloc/types/fuzzer/gralloctypes.cpp +++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp @@ -70,6 +70,7 @@ std::vector<GrallocTypesDecode> GRALLOCTYPES_DECODE_FUNCTIONS { GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeInterlaced), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeChromaSiting), GRALLOCTYPES_DECODE(std::vector<aidl::android::hardware::graphics::common::PlaneLayout>, ::android::gralloc4::decodePlaneLayouts), + GRALLOCTYPES_DECODE(std::vector<aidl::android::hardware::graphics::common::Rect>, ::android::gralloc4::decodeCrop), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode), GRALLOCTYPES_DECODE(std::optional<aidl::android::hardware::graphics::common::Smpte2086>, ::android::gralloc4::decodeSmpte2086), diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index d8554398c3..5ec4d0df3c 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -89,6 +89,24 @@ inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lh return !(lhs == rhs); } +inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs, + const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + for (size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] != rhs[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs, + const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) { + return !(lhs == rhs); +} + inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs, const aidl::android::hardware::graphics::common::PlaneLayout& rhs) { if (lhs.offsetInBytes != rhs.offsetInBytes) { @@ -115,9 +133,6 @@ inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLay if (lhs.verticalSubsampling != rhs.verticalSubsampling) { return false; } - if (lhs.crop != rhs.crop) { - return false; - } if (lhs.components.size() != rhs.components.size()) { return false; } @@ -286,6 +301,10 @@ static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType Me GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::PLANE_LAYOUTS) }; +static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Crop = { + GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::CROP) +}; + static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Dataspace = { GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::DATASPACE) }; @@ -469,6 +488,9 @@ status_t decodeChromaSiting(const android::hardware::hidl_vec<uint8_t>& chromaSi status_t encodePlaneLayouts(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& planeLayouts, android::hardware::hidl_vec<uint8_t>* outPlaneLayouts); status_t decodePlaneLayouts(const android::hardware::hidl_vec<uint8_t>& planeLayouts, std::vector<aidl::android::hardware::graphics::common::PlaneLayout>* outPlaneLayouts); +status_t encodeCrop(const std::vector<aidl::android::hardware::graphics::common::Rect>& crop, android::hardware::hidl_vec<uint8_t>* outCrop); +status_t decodeCrop(const android::hardware::hidl_vec<uint8_t>& crop, std::vector<aidl::android::hardware::graphics::common::Rect>* outCrop); + status_t encodeDataspace(const aidl::android::hardware::graphics::common::Dataspace& dataspace, android::hardware::hidl_vec<uint8_t>* outDataspace); status_t decodeDataspace(const android::hardware::hidl_vec<uint8_t>& dataspace, aidl::android::hardware::graphics::common::Dataspace* outDataspace); diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp index dbe41f16cc..89cbf4ac4a 100644 --- a/libs/gralloc/types/tests/Gralloc4_test.cpp +++ b/libs/gralloc/types/tests/Gralloc4_test.cpp @@ -321,10 +321,6 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * height; planeLayoutA.horizontalSubsampling = 1; planeLayoutA.verticalSubsampling = 1; - planeLayoutA.crop.left = 0; - planeLayoutA.crop.top = 0; - planeLayoutA.crop.right = width; - planeLayoutA.crop.bottom = height; component.type = gralloc4::PlaneLayoutComponentType_A; component.offsetInBits = 0; @@ -341,11 +337,6 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * height; planeLayoutRGB.horizontalSubsampling = 1; planeLayoutRGB.verticalSubsampling = 1; - planeLayoutRGB.crop.left = 0; - planeLayoutRGB.crop.top = 0; - planeLayoutRGB.crop.right = width; - planeLayoutRGB.crop.bottom = height; - component.type = gralloc4::PlaneLayoutComponentType_R; planeLayoutRGB.components.push_back(component); component.type = gralloc4::PlaneLayoutComponentType_G; @@ -358,6 +349,33 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(planeLayouts, gralloc4::encodePlaneLayouts, gralloc4::decodePlaneLayouts)); } +class Gralloc4TestCrop : public testing::Test { }; + +TEST_F(Gralloc4TestCrop, Crop) { + std::vector<Rect> crops; + Rect crop1, crop2, crop3; + + crop1.left = 0; + crop1.top = 0; + crop1.right = 64; + crop1.bottom = 64; + crops.push_back(crop1); + + crop2.left = std::numeric_limits<int32_t>::min(); + crop2.top = 0xFF; + crop2.right = std::numeric_limits<int32_t>::max(); + crop2.bottom = 0xFFFF; + crops.push_back(crop2); + + crop3.left = 0; + crop3.top = 0; + crop3.right = -1; + crop3.bottom = -1; + crops.push_back(crop3); + + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(crops, gralloc4::encodeCrop, gralloc4::decodeCrop)); +} + class Gralloc4TestDataspace : public testing::TestWithParam<Dataspace> { }; INSTANTIATE_TEST_CASE_P( diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 493a7093a0..b2cce7c932 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -148,6 +148,9 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis } } + mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames); + mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames); + mStatsDelegate->statsEventBuild(event); } clearLayersLocked(); diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter index 2bedd7d602..cf7d570165 100644 --- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter +++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter @@ -1,5 +1,5 @@ { "presubmit": { - "filter": "*:-LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3" + "filter": "" } } diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 91a40d012c..fb2e3bddc4 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -892,12 +892,20 @@ MATCHER_P2(BytesEq, bytes, size, "") { return expected == actual; } -TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) { +TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { + constexpr size_t LATE_ACQUIRE_FRAMES = 2; + constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); mTimeStats->onBootFinished(); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); + for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { + mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); + } + for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) { + mTimeStats->incrementBadDesiredPresent(LAYER_ID_0); + } insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); EXPECT_THAT(mDelegate->mAtomTags, @@ -955,6 +963,9 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) { BytesEq((const uint8_t*)expectedPostToAcquire.c_str(), expectedPostToAcquire.size()), expectedPostToAcquire.size())); + EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES)); + EXPECT_CALL(*mDelegate, + statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES)); EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); } EXPECT_EQ(AStatsManager_PULL_SUCCESS, |