diff options
31 files changed, 556 insertions, 65 deletions
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md index eb0d898be1..3606827a4d 100644 --- a/cmds/bugreportz/readme.md +++ b/cmds/bugreportz/readme.md @@ -1,6 +1,6 @@ # bugreportz protocol -`bugreportz` is used to generate a zippped bugreport whose path is passed back to `adb`, using +`bugreportz` is used to generate a zipped bugreport whose path is passed back to `adb`, using the simple protocol defined below. # Version 1.1 diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING index 839a2c3023..649a13ee1e 100644 --- a/cmds/dumpstate/TEST_MAPPING +++ b/cmds/dumpstate/TEST_MAPPING @@ -9,15 +9,15 @@ ] }, { - "name": "dumpstate_smoke_test" - }, - { "name": "dumpstate_test" } ], "postsubmit": [ { "name": "BugreportManagerTestCases" + }, + { + "name": "dumpstate_smoke_test" } ], "imports": [ diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 2c8adc7126..faf67fd92f 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -125,8 +125,6 @@ static std::once_flag flag; namespace { -constexpr const char* kDump = "android.permission.DUMP"; - static binder::Status ok() { return binder::Status::ok(); } @@ -150,19 +148,6 @@ static binder::Status error(uint32_t code, const std::string& msg) { return binder::Status::fromServiceSpecificError(code, String8(msg.c_str())); } -binder::Status checkPermission(const char* permission) { - pid_t pid; - uid_t uid; - - if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid), - reinterpret_cast<int32_t*>(&uid))) { - return ok(); - } else { - return exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); - } -} - binder::Status checkUid(uid_t expectedUid) { uid_t uid = IPCThreadState::self()->getCallingUid(); if (uid == expectedUid || uid == AID_ROOT) { @@ -400,13 +385,7 @@ status_t InstalldNativeService::start() { return android::OK; } -status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) { - const binder::Status dump_permission = checkPermission(kDump); - if (!dump_permission.isOk()) { - dprintf(fd, "%s\n", dump_permission.toString8().c_str()); - return PERMISSION_DENIED; - } - +status_t InstalldNativeService::dump(int fd, const Vector<String16>& /* args */) { { std::lock_guard<std::recursive_mutex> lock(mMountsLock); dprintf(fd, "Storage mounts:\n"); diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 3cfe5297ca..07273835f9 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -762,4 +762,10 @@ Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outRet return Status::ok(); } +void ServiceManager::clear() { + mNameToService.clear(); + mNameToRegistrationCallback.clear(); + mNameToClientCallback.clear(); +} + } // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 5e403194d7..c6db697a89 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -58,6 +58,12 @@ public: void binderDied(const wp<IBinder>& who) override; void handleClientCallbacks(); + /** + * This API is added for debug purposes. It clears members which hold service and callback + * information. + */ + void clear(); + protected: virtual void tryStartService(const std::string& name); diff --git a/cmds/servicemanager/ServiceManagerFuzzer.cpp b/cmds/servicemanager/ServiceManagerFuzzer.cpp index 39f8522f84..b76a6bd3cd 100644 --- a/cmds/servicemanager/ServiceManagerFuzzer.cpp +++ b/cmds/servicemanager/ServiceManagerFuzzer.cpp @@ -29,6 +29,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { auto accessPtr = std::make_unique<Access>(); auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr)); fuzzService(serviceManager, FuzzedDataProvider(data, size)); + serviceManager->clear(); return 0; } diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 7080c7b958..df965ab65f 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -76,6 +76,7 @@ cc_defaults { srcs: [ "Binder.cpp", + "BinderRecordReplay.cpp", "BpBinder.cpp", "Debug.cpp", "FdTrigger.cpp", @@ -148,7 +149,10 @@ cc_defaults { }, debuggable: { - cflags: ["-DBINDER_RPC_DEV_SERVERS"], + cflags: [ + "-DBINDER_RPC_DEV_SERVERS", + "-DBINDER_ENABLE_RECORDING", + ], }, }, diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 402995717c..481d704f1c 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -21,6 +21,7 @@ #include <android-base/logging.h> #include <android-base/unique_fd.h> +#include <binder/BinderRecordReplay.h> #include <binder/BpBinder.h> #include <binder/IInterface.h> #include <binder/IPCThreadState.h> @@ -28,7 +29,9 @@ #include <binder/IShellCallback.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> +#include <cutils/compiler.h> #include <private/android_filesystem_config.h> +#include <pthread.h> #include <utils/misc.h> #include <inttypes.h> @@ -60,6 +63,12 @@ bool kEnableRpcDevServers = true; bool kEnableRpcDevServers = false; #endif +#ifdef BINDER_ENABLE_RECORDING +bool kEnableRecording = true; +#else +bool kEnableRecording = false; +#endif + // Log any reply transactions for which the data exceeds this size #define LOG_REPLIES_OVER_SIZE (300 * 1024) // --------------------------------------------------------------------------- @@ -265,11 +274,13 @@ public: Mutex mLock; std::set<sp<RpcServerLink>> mRpcServerLinks; BpBinder::ObjectManager mObjects; + + android::base::unique_fd mRecordingFd; }; // --------------------------------------------------------------------------- -BBinder::BBinder() : mExtras(nullptr), mStability(0), mParceled(false) {} +BBinder::BBinder() : mExtras(nullptr), mStability(0), mParceled(false), mRecordingOn(false) {} bool BBinder::isBinderAlive() const { @@ -281,6 +292,63 @@ status_t BBinder::pingBinder() return NO_ERROR; } +status_t BBinder::startRecordingTransactions(const Parcel& data) { + if (!kEnableRecording) { + ALOGW("Binder recording disallowed because recording is not enabled"); + return INVALID_OPERATION; + } + if (!kEnableKernelIpc) { + ALOGW("Binder recording disallowed because kernel binder is not enabled"); + return INVALID_OPERATION; + } + uid_t uid = IPCThreadState::self()->getCallingUid(); + if (uid != AID_ROOT) { + ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid); + return PERMISSION_DENIED; + } + Extras* e = getOrCreateExtras(); + AutoMutex lock(e->mLock); + if (mRecordingOn) { + LOG(INFO) << "Could not start Binder recording. Another is already in progress."; + return INVALID_OPERATION; + } else { + status_t readStatus = data.readUniqueFileDescriptor(&(e->mRecordingFd)); + if (readStatus != OK) { + return readStatus; + } + mRecordingOn = true; + LOG(INFO) << "Started Binder recording."; + return NO_ERROR; + } +} + +status_t BBinder::stopRecordingTransactions() { + if (!kEnableRecording) { + ALOGW("Binder recording disallowed because recording is not enabled"); + return INVALID_OPERATION; + } + if (!kEnableKernelIpc) { + ALOGW("Binder recording disallowed because kernel binder is not enabled"); + return INVALID_OPERATION; + } + uid_t uid = IPCThreadState::self()->getCallingUid(); + if (uid != AID_ROOT) { + ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid); + return PERMISSION_DENIED; + } + Extras* e = getOrCreateExtras(); + AutoMutex lock(e->mLock); + if (mRecordingOn) { + e->mRecordingFd.reset(); + mRecordingOn = false; + LOG(INFO) << "Stopped Binder recording."; + return NO_ERROR; + } else { + LOG(INFO) << "Could not stop Binder recording. One is not in progress."; + return INVALID_OPERATION; + } +} + const String16& BBinder::getInterfaceDescriptor() const { static StaticString16 sBBinder(u"BBinder"); @@ -303,6 +371,12 @@ status_t BBinder::transact( case PING_TRANSACTION: err = pingBinder(); break; + case START_RECORDING_TRANSACTION: + err = startRecordingTransactions(data); + break; + case STOP_RECORDING_TRANSACTION: + err = stopRecordingTransactions(); + break; case EXTENSION_TRANSACTION: CHECK(reply != nullptr); err = reply->writeStrongBinder(getExtension()); @@ -329,6 +403,26 @@ status_t BBinder::transact( } } + if (CC_UNLIKELY(kEnableKernelIpc && mRecordingOn && code != START_RECORDING_TRANSACTION)) { + Extras* e = mExtras.load(std::memory_order_acquire); + AutoMutex lock(e->mLock); + if (mRecordingOn) { + Parcel emptyReply; + auto transaction = + android::binder::debug::RecordedTransaction::fromDetails(code, flags, data, + reply ? *reply + : emptyReply, + err); + if (transaction) { + if (status_t err = transaction->dumpToFile(e->mRecordingFd); err != NO_ERROR) { + LOG(INFO) << "Failed to dump RecordedTransaction to file with error " << err; + } + } else { + LOG(INFO) << "Failed to create RecordedTransaction object."; + } + } + } + return err; } diff --git a/libs/binder/BinderRecordReplay.cpp b/libs/binder/BinderRecordReplay.cpp new file mode 100644 index 0000000000..90c02a80b9 --- /dev/null +++ b/libs/binder/BinderRecordReplay.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <binder/BinderRecordReplay.h> +#include <algorithm> + +using android::Parcel; +using android::base::unique_fd; +using android::binder::debug::RecordedTransaction; + +#define PADDING8(s) ((8 - (s) % 8) % 8) + +static_assert(PADDING8(0) == 0); +static_assert(PADDING8(1) == 7); +static_assert(PADDING8(7) == 1); +static_assert(PADDING8(8) == 0); + +// Transactions are sequentially recorded to the file descriptor in the following format: +// +// RecordedTransaction.TransactionHeader (32 bytes) +// Sent Parcel data (getDataSize() bytes) +// padding (enough bytes to align the reply Parcel data to 8 bytes) +// Reply Parcel data (getReplySize() bytes) +// padding (enough bytes to align the next header to 8 bytes) +// [repeats with next transaction] +// +// Warning: This format is non-stable + +RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept { + mHeader = {t.getCode(), t.getFlags(), t.getDataSize(), + t.getReplySize(), t.getReturnedStatus(), t.getVersion()}; + mSent.setData(t.getDataParcel().data(), t.getDataSize()); + mReply.setData(t.getReplyParcel().data(), t.getReplySize()); +} + +std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t code, uint32_t flags, + const Parcel& dataParcel, + const Parcel& replyParcel, + status_t err) { + RecordedTransaction t; + t.mHeader = {code, + flags, + static_cast<uint64_t>(dataParcel.dataSize()), + static_cast<uint64_t>(replyParcel.dataSize()), + static_cast<int32_t>(err), + dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0)}; + + if (t.mSent.setData(dataParcel.data(), t.getDataSize()) != android::NO_ERROR) { + LOG(INFO) << "Failed to set sent parcel data."; + return std::nullopt; + } + + if (t.mReply.setData(replyParcel.data(), t.getReplySize()) != android::NO_ERROR) { + LOG(INFO) << "Failed to set reply parcel data."; + return std::nullopt; + } + + return std::optional<RecordedTransaction>(std::move(t)); +} + +std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) { + RecordedTransaction t; + if (!android::base::ReadFully(fd, &t.mHeader, sizeof(mHeader))) { + LOG(INFO) << "Failed to read transactionHeader from fd " << fd.get(); + return std::nullopt; + } + if (t.getVersion() != 0) { + LOG(INFO) << "File corrupted: transaction version is not 0."; + return std::nullopt; + } + + std::vector<uint8_t> bytes; + bytes.resize(t.getDataSize()); + if (!android::base::ReadFully(fd, bytes.data(), t.getDataSize())) { + LOG(INFO) << "Failed to read sent parcel data from fd " << fd.get(); + return std::nullopt; + } + if (t.mSent.setData(bytes.data(), t.getDataSize()) != android::NO_ERROR) { + LOG(INFO) << "Failed to set sent parcel data."; + return std::nullopt; + } + + uint8_t padding[7]; + if (!android::base::ReadFully(fd, padding, PADDING8(t.getDataSize()))) { + LOG(INFO) << "Failed to read sent parcel padding from fd " << fd.get(); + return std::nullopt; + } + if (std::any_of(padding, padding + 7, [](uint8_t i) { return i != 0; })) { + LOG(INFO) << "File corrupted: padding isn't 0."; + return std::nullopt; + } + + bytes.resize(t.getReplySize()); + if (!android::base::ReadFully(fd, bytes.data(), t.getReplySize())) { + LOG(INFO) << "Failed to read reply parcel data from fd " << fd.get(); + return std::nullopt; + } + if (t.mReply.setData(bytes.data(), t.getReplySize()) != android::NO_ERROR) { + LOG(INFO) << "Failed to set reply parcel data."; + return std::nullopt; + } + + if (!android::base::ReadFully(fd, padding, PADDING8(t.getReplySize()))) { + LOG(INFO) << "Failed to read parcel padding from fd " << fd.get(); + return std::nullopt; + } + if (std::any_of(padding, padding + 7, [](uint8_t i) { return i != 0; })) { + LOG(INFO) << "File corrupted: padding isn't 0."; + return std::nullopt; + } + + return std::optional<RecordedTransaction>(std::move(t)); +} + +android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { + if (!android::base::WriteFully(fd, &mHeader, sizeof(mHeader))) { + LOG(INFO) << "Failed to write transactionHeader to fd " << fd.get(); + return UNKNOWN_ERROR; + } + if (!android::base::WriteFully(fd, mSent.data(), getDataSize())) { + LOG(INFO) << "Failed to write sent parcel data to fd " << fd.get(); + return UNKNOWN_ERROR; + } + const uint8_t zeros[7] = {0}; + if (!android::base::WriteFully(fd, zeros, PADDING8(getDataSize()))) { + LOG(INFO) << "Failed to write sent parcel padding to fd " << fd.get(); + return UNKNOWN_ERROR; + } + if (!android::base::WriteFully(fd, mReply.data(), getReplySize())) { + LOG(INFO) << "Failed to write reply parcel data to fd " << fd.get(); + return UNKNOWN_ERROR; + } + if (!android::base::WriteFully(fd, zeros, PADDING8(getReplySize()))) { + LOG(INFO) << "Failed to write reply parcel padding to fd " << fd.get(); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + +uint32_t RecordedTransaction::getCode() const { + return mHeader.code; +} + +uint32_t RecordedTransaction::getFlags() const { + return mHeader.flags; +} + +uint64_t RecordedTransaction::getDataSize() const { + return mHeader.dataSize; +} + +uint64_t RecordedTransaction::getReplySize() const { + return mHeader.replySize; +} + +int32_t RecordedTransaction::getReturnedStatus() const { + return mHeader.statusReturned; +} + +uint32_t RecordedTransaction::getVersion() const { + return mHeader.version; +} + +const Parcel& RecordedTransaction::getDataParcel() const { + return mSent; +} + +const Parcel& RecordedTransaction::getReplyParcel() const { + return mReply; +} diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index d9b723108e..54d24457d4 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -30,6 +30,8 @@ #include "BuildFlags.h" +#include <android-base/file.h> + //#undef ALOGV //#define ALOGV(...) fprintf(stderr, __VA_ARGS__) @@ -299,6 +301,18 @@ status_t BpBinder::pingBinder() return transact(PING_TRANSACTION, data, &reply); } +status_t BpBinder::startRecordingBinder(const android::base::unique_fd& fd) { + Parcel send, reply; + send.writeUniqueFileDescriptor(fd); + return transact(START_RECORDING_TRANSACTION, send, &reply); +} + +status_t BpBinder::stopRecordingBinder() { + Parcel data, reply; + data.markForBinder(sp<BpBinder>::fromExisting(this)); + return transact(STOP_RECORDING_TRANSACTION, data, &reply); +} + status_t BpBinder::dump(int fd, const Vector<String16>& args) { Parcel send; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index b50cfb3d19..bfcf39ad30 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1318,6 +1318,13 @@ status_t IPCThreadState::executeCommand(int32_t cmd) LOG_ONEWAY("Sending reply to %d!", mCallingPid); if (error < NO_ERROR) reply.setError(error); + // b/238777741: clear buffer before we send the reply. + // Otherwise, there is a race where the client may + // receive the reply and send another transaction + // here and the space used by this transaction won't + // be freed for the client. + buffer.setDataSize(0); + constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF; sendReply(reply, (tr.flags & kForwardReplyFlags)); } else { diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index c0a8d74195..05db7743f2 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "ServiceManager" +#define LOG_TAG "ServiceManagerCppClient" #include <binder/IServiceManager.h> @@ -380,6 +380,13 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) if (Status status = realGetService(name, &out); !status.isOk()) { ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(), status.toString8().c_str()); + if (0 == ProcessState::self()->getThreadPoolMaxTotalThreadCount()) { + ALOGW("Got service, but may be racey because we could not wait efficiently for it. " + "Threadpool has 0 guaranteed threads. " + "Is the threadpool configured properly? " + "See ProcessState::startThreadPool and " + "ProcessState::setThreadPoolMaxThreadCount."); + } return nullptr; } if (out != nullptr) return out; @@ -410,7 +417,9 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) if (waiter->mBinder != nullptr) return waiter->mBinder; } - ALOGW("Waited one second for %s (is service started? are binder threads started and available?)", name.c_str()); + ALOGW("Waited one second for %s (is service started? Number of threads started in the " + "threadpool: %zu. Are binder threads started and available?)", + name.c_str(), ProcessState::self()->getThreadPoolMaxTotalThreadCount()); // Handle race condition for lazy services. Here is what can happen: // - the service dies (not processed by init yet). diff --git a/libs/binder/RpcTrusty.cpp b/libs/binder/RpcTrusty.cpp index ea49eef676..3b53b05991 100644 --- a/libs/binder/RpcTrusty.cpp +++ b/libs/binder/RpcTrusty.cpp @@ -26,8 +26,12 @@ namespace android { using android::base::unique_fd; -sp<IBinder> RpcTrustyConnect(const char* device, const char* port) { +sp<RpcSession> RpcTrustyConnectWithSessionInitializer( + const char* device, const char* port, + std::function<void(sp<RpcSession>&)> sessionInitializer) { auto session = RpcSession::make(RpcTransportCtxFactoryTipcAndroid::make()); + // using the callback to initialize the session + sessionInitializer(session); auto request = [=] { int tipcFd = tipc_connect(device, port); if (tipcFd < 0) { @@ -40,6 +44,11 @@ sp<IBinder> RpcTrustyConnect(const char* device, const char* port) { LOG(ERROR) << "Failed to set up Trusty client. Error: " << statusToString(status).c_str(); return nullptr; } + return session; +} + +sp<IBinder> RpcTrustyConnect(const char* device, const char* port) { + auto session = RpcTrustyConnectWithSessionInitializer(device, port, [](auto) {}); return session->getRootObject(); } diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 88d9ca1d58..08dbd13bf4 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -105,6 +105,12 @@ public: [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd, const sp<IBinder>& keepAliveBinder); + // Start recording transactions to the unique_fd in data. + // See BinderRecordReplay.h for more details. + [[nodiscard]] status_t startRecordingTransactions(const Parcel& data); + // Stop the current recording. + [[nodiscard]] status_t stopRecordingTransactions(); + protected: virtual ~BBinder(); @@ -131,7 +137,7 @@ private: friend ::android::internal::Stability; int16_t mStability; bool mParceled; - uint8_t mReserved0; + bool mRecordingOn; #ifdef __LP64__ int32_t mReserved1; diff --git a/libs/binder/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/BinderRecordReplay.h new file mode 100644 index 0000000000..25ed5e5ff8 --- /dev/null +++ b/libs/binder/include/binder/BinderRecordReplay.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android-base/unique_fd.h> +#include <binder/Parcel.h> +#include <mutex> + +namespace android { + +namespace binder::debug { + +// Warning: Transactions are sequentially recorded to the file descriptor in a +// non-stable format. A detailed description of the recording format can be found in +// BinderRecordReplay.cpp. + +class RecordedTransaction { +public: + // Filled with the first transaction from fd. + static std::optional<RecordedTransaction> fromFile(const android::base::unique_fd& fd); + // Filled with the arguments. + static std::optional<RecordedTransaction> fromDetails(uint32_t code, uint32_t flags, + const Parcel& data, const Parcel& reply, + status_t err); + RecordedTransaction(RecordedTransaction&& t) noexcept; + + [[nodiscard]] status_t dumpToFile(const android::base::unique_fd& fd) const; + + uint32_t getCode() const; + uint32_t getFlags() const; + uint64_t getDataSize() const; + uint64_t getReplySize() const; + int32_t getReturnedStatus() const; + uint32_t getVersion() const; + const Parcel& getDataParcel() const; + const Parcel& getReplyParcel() const; + +private: + RecordedTransaction() = default; + +#pragma clang diagnostic push +#pragma clang diagnostic error "-Wpadded" + struct TransactionHeader { + uint32_t code = 0; + uint32_t flags = 0; + uint64_t dataSize = 0; + uint64_t replySize = 0; + int32_t statusReturned = 0; + uint32_t version = 0; // !0 iff Rpc + }; +#pragma clang diagnostic pop + static_assert(sizeof(TransactionHeader) == 32); + static_assert(sizeof(TransactionHeader) % 8 == 0); + + TransactionHeader mHeader; + Parcel mSent; + Parcel mReply; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" + uint8_t mReserved[40]; +#pragma clang diagnostic pop +}; + +} // namespace binder::debug + +} // namespace android diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 4172cc511e..57e103d39e 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -16,6 +16,7 @@ #pragma once +#include <android-base/unique_fd.h> #include <binder/IBinder.h> #include <utils/Mutex.h> @@ -89,6 +90,12 @@ public: std::optional<int32_t> getDebugBinderHandle() const; + // Start recording transactions to the unique_fd. + // See BinderRecordReplay.h for more details. + status_t startRecordingBinder(const android::base::unique_fd& fd); + // Stop the current recording. + status_t stopRecordingBinder(); + class ObjectManager { public: ObjectManager(); diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 83aaca7f95..e75d548bd8 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -56,6 +56,8 @@ public: LAST_CALL_TRANSACTION = 0x00ffffff, PING_TRANSACTION = B_PACK_CHARS('_', 'P', 'N', 'G'), + START_RECORDING_TRANSACTION = B_PACK_CHARS('_', 'S', 'R', 'D'), + STOP_RECORDING_TRANSACTION = B_PACK_CHARS('_', 'E', 'R', 'D'), DUMP_TRANSACTION = B_PACK_CHARS('_', 'D', 'M', 'P'), SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_', 'C', 'M', 'D'), INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'), diff --git a/libs/binder/include_trusty/binder/RpcTrusty.h b/libs/binder/include_trusty/binder/RpcTrusty.h index f124e0c824..b034b9b65b 100644 --- a/libs/binder/include_trusty/binder/RpcTrusty.h +++ b/libs/binder/include_trusty/binder/RpcTrusty.h @@ -22,4 +22,8 @@ namespace android { sp<IBinder> RpcTrustyConnect(const char* device, const char* port); +sp<RpcSession> RpcTrustyConnectWithSessionInitializer( + const char* device, const char* port, + std::function<void(sp<RpcSession>&)> sessionInitializer); + } // namespace android diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 0ec618352a..a135796179 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -30,6 +30,7 @@ rust_library { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.rkpd", "com.android.uwb", "com.android.virt", ], @@ -80,6 +81,7 @@ rust_library { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.rkpd", "com.android.uwb", "com.android.virt", ], @@ -138,6 +140,7 @@ rust_bindgen { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.rkpd", "com.android.uwb", "com.android.virt", ], diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index f16939036c..5ebc27f694 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -16,7 +16,7 @@ rust_library { ], rustlibs: [ "libbinder_ndk_sys", - "libbinder_rpc_unstable_bindgen", + "libbinder_rpc_unstable_bindgen_sys", "libbinder_rs", "libdowncast_rs", "liblibc", @@ -29,6 +29,35 @@ rust_library { min_sdk_version: "Tiramisu", } +// Build a separate rust_library rather than depending directly on libbinder_rpc_unstable_bindgen, +// to work around the fact that rust_bindgen targets only produce rlibs and not dylibs, which would +// result in duplicate conflicting versions of libbinder_ndk_sys. This will hopefully be fixed in +// the build system, at which point we can delete this target and go back to using +// libbinder_rpc_unstable_bindgen directly. +rust_library { + name: "libbinder_rpc_unstable_bindgen_sys", + crate_name: "binder_rpc_unstable_bindgen", + srcs: [ + ":libbinder_rpc_unstable_bindgen", + ], + visibility: [":__subpackages__"], + rustlibs: [ + "libbinder_ndk_sys", + ], + shared_libs: [ + "libbinder_rpc_unstable", + "libutils", + ], + apex_available: [ + "com.android.compos", + "com.android.uwb", + "com.android.virt", + ], + min_sdk_version: "Tiramisu", + lints: "none", + clippy_lints: "none", +} + // TODO(b/184872979): remove once the RPC Binder API is stabilised. rust_bindgen { name: "libbinder_rpc_unstable_bindgen", @@ -36,6 +65,15 @@ rust_bindgen { crate_name: "binder_rpc_unstable_bindgen", visibility: [":__subpackages__"], source_stem: "bindings", + bindgen_flags: [ + "--blocklist-type", + "AIBinder", + "--raw-line", + "use binder_ndk_sys::AIBinder;", + ], + rustlibs: [ + "libbinder_ndk_sys", + ], shared_libs: [ "libbinder_rpc_unstable", "libutils", @@ -52,6 +90,9 @@ rust_test { name: "libbinder_rpc_unstable_bindgen_test", srcs: [":libbinder_rpc_unstable_bindgen"], crate_name: "binder_rpc_unstable_bindgen", + rustlibs: [ + "libbinder_ndk_sys", + ], test_suites: ["general-tests"], auto_gen_config: true, clippy_lints: "none", diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs index dfc6f06b14..743800beb1 100644 --- a/libs/binder/rust/rpcbinder/src/client.rs +++ b/libs/binder/rust/rpcbinder/src/client.rs @@ -14,10 +14,7 @@ * limitations under the License. */ -use binder::{ - unstable_api::{new_spibinder, AIBinder}, - FromIBinder, SpIBinder, StatusCode, Strong, -}; +use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong}; use std::os::{ raw::{c_int, c_void}, unix::io::RawFd, @@ -27,7 +24,7 @@ use std::os::{ pub fn get_vsock_rpc_service(cid: u32, port: u32) -> Option<SpIBinder> { // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can // safely be taken by new_spibinder. - unsafe { new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port) as *mut AIBinder) } + unsafe { new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port)) } } /// Connects to an RPC Binder server for a particular interface over vsock. @@ -54,7 +51,7 @@ pub fn get_preconnected_rpc_service( new_spibinder(binder_rpc_unstable_bindgen::RpcPreconnectedClient( Some(request_fd_wrapper), param, - ) as *mut AIBinder) + )) } } diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs index d98a439da4..aeb23c60e2 100644 --- a/libs/binder/rust/rpcbinder/src/server.rs +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -14,7 +14,10 @@ * limitations under the License. */ -use binder::{unstable_api::AsNative, SpIBinder}; +use binder::{ + unstable_api::{AIBinder, AsNative}, + SpIBinder, +}; use std::{os::raw, ptr::null_mut}; /// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock @@ -44,7 +47,7 @@ where F: FnOnce(), { fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool { - let service = service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder; + let service = service.as_native_mut(); let param = self.as_void_ptr(); // SAFETY: Service ownership is transferring to the server and won't be valid afterward. @@ -106,10 +109,7 @@ pub fn run_rpc_server_with_factory( } } -unsafe extern "C" fn factory_wrapper( - cid: u32, - context: *mut raw::c_void, -) -> *mut binder_rpc_unstable_bindgen::AIBinder { +unsafe extern "C" fn factory_wrapper(cid: u32, context: *mut raw::c_void) -> *mut AIBinder { // SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by // `run_rpc_server_with_factory`, and we are still within the lifetime of the value it is // pointing to. @@ -117,7 +117,7 @@ unsafe extern "C" fn factory_wrapper( let factory = factory_ptr.as_mut().unwrap(); if let Some(mut service) = factory(cid) { - service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder + service.as_native_mut() } else { null_mut() } diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index 3a6daddffd..dee05d07cf 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -296,7 +296,7 @@ impl<T: Remotable> InterfaceClassMethods for Binder<T> { /// Must be called with a valid pointer to a `T` object. After this call, /// the pointer will be invalid and should not be dereferenced. unsafe extern "C" fn on_destroy(object: *mut c_void) { - Box::from_raw(object as *mut T); + drop(Box::from_raw(object as *mut T)); } /// Called whenever a new, local `AIBinder` object is needed of a specific diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index e460d2c965..92d132f37c 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -605,6 +605,7 @@ cc_test { shared_libs: [ "libbinder", "liblog", + "libcutils", "libutils", "libutilscallstack", "libbase", diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp index a2ab8ab302..55a3916112 100644 --- a/libs/binder/tests/binderAllocationLimits.cpp +++ b/libs/binder/tests/binderAllocationLimits.cpp @@ -20,6 +20,7 @@ #include <binder/Parcel.h> #include <binder/RpcServer.h> #include <binder/RpcSession.h> +#include <cutils/trace.h> #include <gtest/gtest.h> #include <utils/CallStack.h> @@ -223,5 +224,10 @@ int main(int argc, char** argv) { return 1; } ::testing::InitGoogleTest(&argc, argv); + + // if tracing is enabled, take in one-time cost + (void)ATRACE_INIT(); + (void)ATRACE_GET_ENABLED_TAGS(); + return RUN_ALL_TESTS(); } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 5de08bdc00..6e1c8ac16a 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -1161,8 +1161,7 @@ TEST_F(BinderLibTest, VectorSent) { // see ProcessState.cpp BINDER_VM_SIZE = 1MB. // This value is not exposed, but some code in the framework relies on being able to use // buffers near the cap size. -// TODO(b/238777741): why do larger values, like 300K fail sometimes -constexpr size_t kSizeBytesAlmostFull = 100'000; +constexpr size_t kSizeBytesAlmostFull = 950'000; constexpr size_t kSizeBytesOverFull = 1'050'000; TEST_F(BinderLibTest, GargantuanVectorSent) { diff --git a/libs/binderthreadstate/test.cpp b/libs/binderthreadstate/test.cpp index 2f731377f0..df1f35d9a7 100644 --- a/libs/binderthreadstate/test.cpp +++ b/libs/binderthreadstate/test.cpp @@ -73,6 +73,15 @@ static void callAidl(size_t id, int32_t idx) { CHECK(ret.isOk()) << ret; } +static std::string getStackPointerDebugInfo() { + const void* hwbinderSp = android::hardware::IPCThreadState::self()->getServingStackPointer(); + const void* binderSp = android::IPCThreadState::self()->getServingStackPointer(); + + std::stringstream ss; + ss << "(hwbinder sp: " << hwbinderSp << " binder sp: " << binderSp << ")"; + return ss.str(); +} + static inline std::ostream& operator<<(std::ostream& o, const BinderCallType& s) { return o << static_cast<std::underlying_type_t<BinderCallType>>(s); } @@ -88,17 +97,21 @@ public: return android::hardware::Status::ok(); } Return<void> call(int32_t idx) { + bool doCallHidl = thisId == kP1Id && idx % 4 < 2; + LOG(INFO) << "HidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx - << " with tid: " << gettid(); - CHECK_EQ(BinderCallType::HWBINDER, getCurrentServingCall()); + << " with tid: " << gettid() << " calling " << (doCallHidl ? "HIDL" : "AIDL"); + CHECK_EQ(BinderCallType::HWBINDER, getCurrentServingCall()) + << " before call " << getStackPointerDebugInfo(); if (idx > 0) { - if (thisId == kP1Id && idx % 4 < 2) { + if (doCallHidl) { callHidl(otherId, idx - 1); } else { callAidl(otherId, idx - 1); } } - CHECK_EQ(BinderCallType::HWBINDER, getCurrentServingCall()); + CHECK_EQ(BinderCallType::HWBINDER, getCurrentServingCall()) + << " after call " << getStackPointerDebugInfo(); return android::hardware::Status::ok(); } }; @@ -113,17 +126,20 @@ public: return Status::ok(); } Status call(int32_t idx) { + bool doCallHidl = thisId == kP2Id && idx % 4 < 2; LOG(INFO) << "AidlServer CALL " << thisId << " to " << otherId << " at idx: " << idx - << " with tid: " << gettid(); - CHECK_EQ(BinderCallType::BINDER, getCurrentServingCall()); + << " with tid: " << gettid() << " calling " << (doCallHidl ? "HIDL" : "AIDL"); + CHECK_EQ(BinderCallType::BINDER, getCurrentServingCall()) + << " before call " << getStackPointerDebugInfo(); if (idx > 0) { - if (thisId == kP2Id && idx % 4 < 2) { + if (doCallHidl) { callHidl(otherId, idx - 1); } else { callAidl(otherId, idx - 1); } } - CHECK_EQ(BinderCallType::BINDER, getCurrentServingCall()); + CHECK_EQ(BinderCallType::BINDER, getCurrentServingCall()) + << " after call " << getStackPointerDebugInfo(); return Status::ok(); } }; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 13ca9ecd35..4127f7ce10 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -929,6 +929,8 @@ std::ostream& operator<<(std::ostream& out, const MotionEvent& event) { out << ", actionButton=" << std::to_string(event.getActionButton()); } const size_t pointerCount = event.getPointerCount(); + LOG_ALWAYS_FATAL_IF(pointerCount > MAX_POINTERS, "Too many pointers : pointerCount = %zu", + pointerCount); for (size_t i = 0; i < pointerCount; i++) { out << ", id[" << i << "]=" << event.getPointerId(i); float x = event.getX(i); diff --git a/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp index 6f10a67ebd..6a61d3615f 100644 --- a/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp +++ b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp @@ -24,14 +24,14 @@ using namespace android; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider fdp(data, size); - BitTube bittube(size); + sp<BitTube> bittube(new BitTube(size)); Parcel parcel[5]; - bittube.writeToParcel(parcel); + bittube->writeToParcel(parcel); sp<BitTube> tube(new BitTube(size)); - bittube.sendObjects<uint8_t>(tube, data, size); + bittube->sendObjects<uint8_t>(tube, data, size); uint8_t recvData[size]; for (int i = 0; i < size; i++) recvData[i] = fdp.ConsumeIntegral<uint8_t>(); - bittube.recvObjects<uint8_t>(tube, recvData, size); + bittube->recvObjects<uint8_t>(tube, recvData, size); return 0; } diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index f664f2f3a6..62cf2555ca 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -185,7 +185,11 @@ cc_library_shared { "libEGL_getProcAddress", "libEGL_blobCache", ], - ldflags: ["-Wl,--exclude-libs=ALL,--Bsymbolic-functions"], + ldflags: [ + "-Wl,--exclude-libs=libEGL_getProcAddress.a", + "-Wl,--exclude-libs=libEGL_blobCache.a", + "-Wl,--Bsymbolic-functions", + ], export_include_dirs: ["EGL/include"], stubs: { symbol_file: "libEGL.map.txt", diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 5e9427ad87..564acc09f9 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3640,6 +3640,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( target.inputChannel = connection->inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; + const bool wasEmpty = connection->outboundQueue.empty(); + for (size_t i = 0; i < cancelationEvents.size(); i++) { std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]); switch (cancelationEventEntry->type) { @@ -3674,7 +3676,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( InputTarget::FLAG_DISPATCH_AS_IS); } - startDispatchCycleLocked(currentTime, connection); + // If the outbound queue was previously empty, start the dispatch cycle going. + if (wasEmpty && !connection->outboundQueue.empty()) { + startDispatchCycleLocked(currentTime, connection); + } } void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( @@ -3708,6 +3713,8 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( target.inputChannel = connection->inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; + const bool wasEmpty = connection->outboundQueue.empty(); + for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) { switch (downEventEntry->type) { case EventEntry::Type::MOTION: { @@ -3733,8 +3740,10 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target, InputTarget::FLAG_DISPATCH_AS_IS); } - - startDispatchCycleLocked(currentTime, connection); + // If the outbound queue was previously empty, start the dispatch cycle going. + if (wasEmpty && !connection->outboundQueue.empty()) { + startDispatchCycleLocked(currentTime, connection); + } } std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( |