Merge "Fix an arithmetic error when using unsigned"
diff --git a/.clang-format b/.clang-format
index 6725a1f..f63f670 100644
--- a/.clang-format
+++ b/.clang-format
@@ -12,3 +12,6 @@
PenaltyBreakBeforeFirstCallParameter: 100000
SpacesBeforeTrailingComments: 1
IncludeBlocks: Preserve
+
+DerivePointerAlignment: false
+PointerAlignment: Left
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index ff73c94..e54f9d3 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -353,8 +353,16 @@
return false;
}
+ auto vintfFqInstance = vintf::FqInstance::from(fqInstance.string());
+ if (!vintfFqInstance.has_value()) {
+ err() << "Unable to convert " << fqInstance.string() << " to vintf::FqInstance"
+ << std::endl;
+ return false;
+ }
+
std::string e;
- if (!manifest->insertInstance(fqInstance, entry.transport, arch, vintf::HalFormat::HIDL, &e)) {
+ if (!manifest->insertInstance(*vintfFqInstance, entry.transport, arch, vintf::HalFormat::HIDL,
+ &e)) {
err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl;
return false;
}
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index cc038ae..695faf8 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -718,7 +718,8 @@
if (service.guaranteeClient) {
// we have no record of this client
if (!service.hasClients && !hasClients) {
- sendClientCallbackNotifications(serviceName, true);
+ sendClientCallbackNotifications(serviceName, true,
+ "service is guaranteed to be in use");
}
// guarantee is temporary
@@ -729,34 +730,41 @@
if (isCalledOnInterval) {
if (hasClients && !service.hasClients) {
// client was retrieved in some other way
- sendClientCallbackNotifications(serviceName, true);
+ sendClientCallbackNotifications(serviceName, true, "we now have a record of a client");
}
// there are no more clients, but the callback has not been called yet
if (!hasClients && service.hasClients) {
- sendClientCallbackNotifications(serviceName, false);
+ sendClientCallbackNotifications(serviceName, false,
+ "we now have no record of a client");
}
}
return count;
}
-void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) {
+void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName,
+ bool hasClients, const char* context) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end()) {
- ALOGW("sendClientCallbackNotifications could not find service %s", serviceName.c_str());
+ ALOGW("sendClientCallbackNotifications could not find service %s when %s",
+ serviceName.c_str(), context);
return;
}
Service& service = serviceIt->second;
- CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients
- << " so we can't tell clients again that we have client: " << hasClients;
+ CHECK(hasClients != service.hasClients)
+ << "Record shows: " << service.hasClients
+ << " so we can't tell clients again that we have client: " << hasClients
+ << " when: " << context;
- ALOGI("Notifying %s they have clients: %d", serviceName.c_str(), hasClients);
+ ALOGI("Notifying %s they %s have clients when %s", serviceName.c_str(),
+ hasClients ? "do" : "don't", context);
auto ccIt = mNameToClientCallback.find(serviceName);
CHECK(ccIt != mNameToClientCallback.end())
- << "sendClientCallbackNotifications could not find callbacks for service ";
+ << "sendClientCallbackNotifications could not find callbacks for service when "
+ << context;
for (const auto& callback : ccIt->second) {
callback->onClients(service.binder, hasClients);
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index b24c11c..f9d4f8f 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -92,8 +92,9 @@
ServiceCallbackMap::iterator* it,
bool* found);
ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval);
- // Also updates mHasClients (of what the last callback was)
- void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients);
+ // Also updates mHasClients (of what the last callback was)
+ void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients,
+ const char* context);
// removes a callback from mNameToClientCallback, deleting the entry if the vector is empty
// this updates the iterator to the next location
void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 28369d6..cebaf17 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -74,9 +74,11 @@
name: "libbinder_common_defaults",
host_supported: true,
+ // for vndbinder and binderRpcTest
+ vendor_available: true,
+
srcs: [
"Binder.cpp",
- "BinderRecordReplay.cpp",
"BpBinder.cpp",
"Debug.cpp",
"FdTrigger.cpp",
@@ -84,6 +86,7 @@
"IResultReceiver.cpp",
"Parcel.cpp",
"ParcelFileDescriptor.cpp",
+ "RecordedTransaction.cpp",
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
@@ -195,18 +198,26 @@
],
}
-cc_library_shared {
- name: "libbinder_on_trusty_mock",
- defaults: ["libbinder_common_defaults"],
+cc_library_headers {
+ name: "trusty_mock_headers",
+ vendor_available: true,
+ host_supported: true,
- srcs: [
- // Trusty-specific files
- "trusty/logging.cpp",
- "trusty/OS.cpp",
- "trusty/RpcServerTrusty.cpp",
- "trusty/RpcTransportTipcTrusty.cpp",
- "trusty/TrustyStatus.cpp",
- "trusty/socket.cpp",
+ export_include_dirs: [
+ "trusty/include",
+ "trusty/include_mock",
+ ],
+
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+cc_defaults {
+ name: "trusty_mock_defaults",
+
+ header_libs: [
+ "trusty_mock_headers",
],
cflags: [
@@ -227,16 +238,29 @@
],
rtti: false,
- local_include_dirs: [
- "trusty/include",
- "trusty/include_mock",
- ],
-
visibility: [
":__subpackages__",
],
}
+cc_library_shared {
+ name: "libbinder_on_trusty_mock",
+ defaults: [
+ "libbinder_common_defaults",
+ "trusty_mock_defaults",
+ ],
+
+ srcs: [
+ // Trusty-specific files
+ "trusty/logging.cpp",
+ "trusty/OS.cpp",
+ "trusty/RpcServerTrusty.cpp",
+ "trusty/RpcTransportTipcTrusty.cpp",
+ "trusty/TrustyStatus.cpp",
+ "trusty/socket.cpp",
+ ],
+}
+
cc_defaults {
name: "libbinder_kernel_defaults",
srcs: [
@@ -275,8 +299,6 @@
version_script: "libbinder.map",
- // for vndbinder
- vendor_available: true,
vndk: {
enabled: true,
},
@@ -439,6 +461,7 @@
cc_library_static {
name: "libbinder_tls_static",
defaults: ["libbinder_tls_defaults"],
+ vendor_available: true,
visibility: [
":__subpackages__",
],
@@ -517,6 +540,7 @@
visibility: [
":__subpackages__",
"//packages/modules/Virtualization:__subpackages__",
+ "//device/google/cuttlefish/shared/minidroid:__subpackages__",
],
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 5e725a9..3e49656 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -21,13 +21,13 @@
#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>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
+#include <binder/RecordedTransaction.h>
#include <binder/RpcServer.h>
#include <cutils/compiler.h>
#include <private/android_filesystem_config.h>
@@ -407,11 +407,11 @@
AutoMutex lock(e->mLock);
if (mRecordingOn) {
Parcel emptyReply;
- auto transaction =
- android::binder::debug::RecordedTransaction::fromDetails(code, flags, data,
- reply ? *reply
- : emptyReply,
- err);
+ timespec ts;
+ timespec_get(&ts, TIME_UTC);
+ auto transaction = android::binder::debug::RecordedTransaction::
+ fromDetails(getInterfaceDescriptor(), code, flags, ts, 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;
diff --git a/libs/binder/BinderRecordReplay.cpp b/libs/binder/BinderRecordReplay.cpp
deleted file mode 100644
index 90c02a8..0000000
--- a/libs/binder/BinderRecordReplay.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2022, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#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 1c470a1..d03326e 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -388,7 +388,7 @@
{
if (isRpcBinder()) {
if (rpcSession()->getMaxIncomingThreads() < 1) {
- LOG_ALWAYS_FATAL("Cannot register a DeathRecipient without any incoming connections.");
+ ALOGE("Cannot register a DeathRecipient without any incoming connections.");
return INVALID_OPERATION;
}
} else if constexpr (!kEnableKernelIpc) {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 6d64e1e..da58251 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1221,6 +1221,10 @@
return NO_ERROR;
}
+ ALOGE_IF(mProcess->mDriverFD >= 0,
+ "Driver returned error (%s). This is a bug in either libbinder or the driver. This "
+ "thread's connection to %s will no longer work.",
+ statusToString(err).c_str(), mProcess->mDriverName.c_str());
return err;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 44ff62b..0aca163 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -375,6 +375,10 @@
return (mDataSize > mDataPos ? mDataSize : mDataPos);
}
+size_t Parcel::dataBufferSize() const {
+ return mDataSize;
+}
+
size_t Parcel::dataAvail() const
{
size_t result = dataSize() - dataPosition();
diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp
new file mode 100644
index 0000000..2e70304
--- /dev/null
+++ b/libs/binder/RecordedTransaction.cpp
@@ -0,0 +1,364 @@
+/*
+ * 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 <android-base/unique_fd.h>
+#include <binder/RecordedTransaction.h>
+#include <sys/mman.h>
+#include <algorithm>
+
+using android::Parcel;
+using android::base::borrowed_fd;
+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 a file descriptor.
+//
+// An individual RecordedTransaction is written with the following format:
+//
+// WARNING: Though the following format is designed to be stable and
+// extensible, it is under active development and should be considered
+// unstable until this warning is removed.
+//
+// A RecordedTransaction is written to a file as a sequence of Chunks.
+//
+// A Chunk consists of a ChunkDescriptor, Data, Padding, and a Checksum.
+//
+// The ChunkDescriptor identifies the type of Data in the chunk, and the size
+// of the Data.
+//
+// The Data may be any uint32 number of bytes in length in [0-0xfffffff0].
+//
+// Padding is between [0-7] zero-bytes after the Data such that the Chunk ends
+// on an 8-byte boundary. The ChunkDescriptor's dataSize does not include the
+// size of Padding.
+//
+// The checksum is a 64-bit wide XOR of all previous data from the start of the
+// ChunkDescriptor to the end of Padding.
+//
+// ┌───────────────────────────┐
+// │Chunk │
+// │┌────────────────────────┐ │
+// ││ChunkDescriptor │ │
+// ││┌───────────┬──────────┐│ │
+// │││chunkType │dataSize ├┼─┼─┐
+// │││uint32_t │uint32_t ││ │ │
+// ││└───────────┴──────────┘│ │ │
+// │└────────────────────────┘ │ │
+// │┌─────────────────────────┐│ │
+// ││Data ││ │
+// ││bytes * dataSize │◀─┘
+// ││ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤│
+// ││ Padding ││
+// │└───┴─────────────────────┘│
+// │┌─────────────────────────┐│
+// ││checksum ││
+// ││uint64_t ││
+// │└─────────────────────────┘│
+// └───────────────────────────┘
+//
+// A RecordedTransaction is written as a Header Chunk with fields about the
+// transaction, a Data Parcel chunk, a Reply Parcel Chunk, and an End Chunk.
+// ┌──────────────────────┐
+// │ Header Chunk │
+// ├──────────────────────┤
+// │ Sent Parcel Chunk │
+// ├──────────────────────┤
+// │ Reply Parcel Chunk │
+// ├──────────────────────┤
+// ║ End Chunk ║
+// ╚══════════════════════╝
+//
+// On reading a RecordedTransaction, an unrecognized chunk is checksummed
+// then skipped according to size information in the ChunkDescriptor. Chunks
+// are read and either assimilated or skipped until an End Chunk is
+// encountered. This has three notable implications:
+//
+// 1. Older and newer implementations should be able to read one another's
+// Transactions, though there will be loss of information.
+// 2. With the exception of the End Chunk, Chunks can appear in any order
+// and even repeat, though this is not recommended.
+// 3. If any Chunk is repeated, old values will be overwritten by versions
+// encountered later in the file.
+//
+// No effort is made to ensure the expected chunks are present. A single
+// End Chunk may therefore produce an empty, meaningless RecordedTransaction.
+
+RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept {
+ mData = t.mData;
+ mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize());
+ mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize());
+}
+
+std::optional<RecordedTransaction> RecordedTransaction::fromDetails(
+ const String16& interfaceName, uint32_t code, uint32_t flags, timespec timestamp,
+ const Parcel& dataParcel, const Parcel& replyParcel, status_t err) {
+ RecordedTransaction t;
+ t.mData.mHeader = {code,
+ flags,
+ static_cast<int32_t>(err),
+ dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0),
+ static_cast<int64_t>(timestamp.tv_sec),
+ static_cast<int32_t>(timestamp.tv_nsec),
+ 0};
+
+ t.mData.mInterfaceName = std::string(String8(interfaceName).string());
+ if (interfaceName.size() != t.mData.mInterfaceName.size()) {
+ LOG(ERROR) << "Interface Name is not valid. Contains characters that aren't single byte "
+ "utf-8: "
+ << interfaceName;
+ return std::nullopt;
+ }
+
+ if (t.mSent.setData(dataParcel.data(), dataParcel.dataSize()) != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to set sent parcel data.";
+ return std::nullopt;
+ }
+
+ if (t.mReply.setData(replyParcel.data(), replyParcel.dataSize()) != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to set reply parcel data.";
+ return std::nullopt;
+ }
+
+ return std::optional<RecordedTransaction>(std::move(t));
+}
+
+enum {
+ HEADER_CHUNK = 1,
+ DATA_PARCEL_CHUNK = 2,
+ REPLY_PARCEL_CHUNK = 3,
+ INTERFACE_NAME_CHUNK = 4,
+ END_CHUNK = 0x00ffffff,
+};
+
+struct ChunkDescriptor {
+ uint32_t chunkType = 0;
+ uint32_t dataSize = 0;
+};
+static_assert(sizeof(ChunkDescriptor) % 8 == 0);
+
+constexpr uint32_t kMaxChunkDataSize = 0xfffffff0;
+typedef uint64_t transaction_checksum_t;
+
+static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut,
+ transaction_checksum_t* sum) {
+ if (!android::base::ReadFully(fd, chunkOut, sizeof(ChunkDescriptor))) {
+ LOG(ERROR) << "Failed to read Chunk Descriptor from fd " << fd.get();
+ return android::UNKNOWN_ERROR;
+ }
+
+ *sum ^= *reinterpret_cast<transaction_checksum_t*>(chunkOut);
+ return android::NO_ERROR;
+}
+
+std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) {
+ RecordedTransaction t;
+ ChunkDescriptor chunk;
+ const long pageSize = sysconf(_SC_PAGE_SIZE);
+ do {
+ transaction_checksum_t checksum = 0;
+ if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) {
+ LOG(ERROR) << "Failed to read chunk descriptor.";
+ return std::nullopt;
+ }
+ off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR);
+ off_t mmapPageAlignedStart = (fdCurrentPosition / pageSize) * pageSize;
+ off_t mmapPayloadStartOffset = fdCurrentPosition - mmapPageAlignedStart;
+
+ if (chunk.dataSize > kMaxChunkDataSize) {
+ LOG(ERROR) << "Chunk data exceeds maximum size.";
+ return std::nullopt;
+ }
+
+ size_t chunkPayloadSize =
+ chunk.dataSize + PADDING8(chunk.dataSize) + sizeof(transaction_checksum_t);
+
+ if (PADDING8(chunkPayloadSize) != 0) {
+ LOG(ERROR) << "Invalid chunk size, not aligned " << chunkPayloadSize;
+ return std::nullopt;
+ }
+
+ transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>(
+ mmap(NULL, chunkPayloadSize + mmapPayloadStartOffset, PROT_READ, MAP_SHARED,
+ fd.get(), mmapPageAlignedStart));
+ payloadMap += mmapPayloadStartOffset /
+ sizeof(transaction_checksum_t); // Skip chunk descriptor and required mmap
+ // page-alignment
+ if (payloadMap == MAP_FAILED) {
+ LOG(ERROR) << "Memory mapping failed for fd " << fd.get() << ": " << errno << " "
+ << strerror(errno);
+ return std::nullopt;
+ }
+ for (size_t checksumIndex = 0;
+ checksumIndex < chunkPayloadSize / sizeof(transaction_checksum_t); checksumIndex++) {
+ checksum ^= payloadMap[checksumIndex];
+ }
+ if (checksum != 0) {
+ LOG(ERROR) << "Checksum failed.";
+ return std::nullopt;
+ }
+ lseek(fd.get(), chunkPayloadSize, SEEK_CUR);
+
+ switch (chunk.chunkType) {
+ case HEADER_CHUNK: {
+ if (chunk.dataSize != static_cast<uint32_t>(sizeof(TransactionHeader))) {
+ LOG(ERROR) << "Header Chunk indicated size " << chunk.dataSize << "; Expected "
+ << sizeof(TransactionHeader) << ".";
+ return std::nullopt;
+ }
+ t.mData.mHeader = *reinterpret_cast<TransactionHeader*>(payloadMap);
+ break;
+ }
+ case INTERFACE_NAME_CHUNK: {
+ t.mData.mInterfaceName =
+ std::string(reinterpret_cast<char*>(payloadMap), chunk.dataSize);
+ break;
+ }
+ case DATA_PARCEL_CHUNK: {
+ if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap),
+ chunk.dataSize) != android::NO_ERROR) {
+ LOG(ERROR) << "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) {
+ LOG(ERROR) << "Failed to set reply parcel data.";
+ return std::nullopt;
+ }
+ break;
+ }
+ case END_CHUNK:
+ break;
+ default:
+ LOG(INFO) << "Unrecognized chunk.";
+ continue;
+ }
+ } while (chunk.chunkType != END_CHUNK);
+
+ return std::optional<RecordedTransaction>(std::move(t));
+}
+
+android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunkType,
+ size_t byteCount, const uint8_t* data) const {
+ if (byteCount > kMaxChunkDataSize) {
+ LOG(ERROR) << "Chunk data exceeds maximum size";
+ return BAD_VALUE;
+ }
+ ChunkDescriptor descriptor = {.chunkType = chunkType,
+ .dataSize = static_cast<uint32_t>(byteCount)};
+ // Prepare Chunk content as byte *
+ const std::byte* descriptorBytes = reinterpret_cast<const std::byte*>(&descriptor);
+ const std::byte* dataBytes = reinterpret_cast<const std::byte*>(data);
+
+ // Add Chunk to intermediate buffer, except checksum
+ std::vector<std::byte> buffer;
+ buffer.insert(buffer.end(), descriptorBytes, descriptorBytes + sizeof(ChunkDescriptor));
+ buffer.insert(buffer.end(), dataBytes, dataBytes + byteCount);
+ std::byte zero{0};
+ buffer.insert(buffer.end(), PADDING8(byteCount), zero);
+
+ // Calculate checksum from buffer
+ transaction_checksum_t* checksumData = reinterpret_cast<transaction_checksum_t*>(buffer.data());
+ transaction_checksum_t checksumValue = 0;
+ for (size_t idx = 0; idx < (buffer.size() / sizeof(transaction_checksum_t)); idx++) {
+ checksumValue ^= checksumData[idx];
+ }
+
+ // Write checksum to buffer
+ std::byte* checksumBytes = reinterpret_cast<std::byte*>(&checksumValue);
+ buffer.insert(buffer.end(), checksumBytes, checksumBytes + sizeof(transaction_checksum_t));
+
+ // Write buffer to file
+ if (!android::base::WriteFully(fd, buffer.data(), buffer.size())) {
+ LOG(ERROR) << "Failed to write chunk fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const {
+ if (NO_ERROR !=
+ writeChunk(fd, HEADER_CHUNK, sizeof(TransactionHeader),
+ reinterpret_cast<const uint8_t*>(&(mData.mHeader)))) {
+ LOG(ERROR) << "Failed to write transactionHeader to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ if (NO_ERROR !=
+ writeChunk(fd, INTERFACE_NAME_CHUNK, mData.mInterfaceName.size() * sizeof(uint8_t),
+ reinterpret_cast<const uint8_t*>(mData.mInterfaceName.c_str()))) {
+ LOG(INFO) << "Failed to write Interface Name Chunk to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+
+ if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataSize(), mSent.data())) {
+ LOG(ERROR) << "Failed to write sent Parcel to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataSize(), mReply.data())) {
+ LOG(ERROR) << "Failed to write reply Parcel to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) {
+ LOG(ERROR) << "Failed to write end chunk to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+const std::string& RecordedTransaction::getInterfaceName() const {
+ return mData.mInterfaceName;
+}
+
+uint32_t RecordedTransaction::getCode() const {
+ return mData.mHeader.code;
+}
+
+uint32_t RecordedTransaction::getFlags() const {
+ return mData.mHeader.flags;
+}
+
+int32_t RecordedTransaction::getReturnedStatus() const {
+ return mData.mHeader.statusReturned;
+}
+
+timespec RecordedTransaction::getTimestamp() const {
+ time_t sec = mData.mHeader.timestampSeconds;
+ int32_t nsec = mData.mHeader.timestampNanoseconds;
+ return (timespec){.tv_sec = sec, .tv_nsec = nsec};
+}
+
+uint32_t RecordedTransaction::getVersion() const {
+ return mData.mHeader.version;
+}
+
+const Parcel& RecordedTransaction::getDataParcel() const {
+ return mSent;
+}
+
+const Parcel& RecordedTransaction::getReplyParcel() const {
+ return mReply;
+}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index b27f102..1ea13f9 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -1036,8 +1036,8 @@
return DEAD_OBJECT;
}
- if (it->second.asyncTodo.size() == 0) return OK;
- if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
+ if (it->second.asyncTodo.size() != 0 &&
+ it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
LOG_RPC_DETAIL("Found next async transaction %" PRIu64 " on %" PRIu64,
it->second.asyncNumber, addr);
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 342e4a3..04cb61f 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -52,6 +52,9 @@
"name": "memunreachable_binder_test"
},
{
+ "name": "resolv_integration_test"
+ },
+ {
"name": "libbinderthreadstateutils_test"
},
{
@@ -96,5 +99,19 @@
{
"name": "binderLibTest"
}
+ ],
+ "kernel-presubmit": [
+ {
+ "name": "binderDriverInterfaceTest"
+ },
+ {
+ "name": "binderLibTest"
+ },
+ {
+ "name": "binderSafeInterfaceTest"
+ },
+ {
+ "name": "memunreachable_binder_test"
+ }
]
}
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 08dbd13..d960a0b 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -106,7 +106,7 @@
const sp<IBinder>& keepAliveBinder);
// Start recording transactions to the unique_fd in data.
- // See BinderRecordReplay.h for more details.
+ // See RecordedTransaction.h for more details.
[[nodiscard]] status_t startRecordingTransactions(const Parcel& data);
// Stop the current recording.
[[nodiscard]] status_t stopRecordingTransactions();
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 57e103d..5496d61 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -91,7 +91,7 @@
std::optional<int32_t> getDebugBinderHandle() const;
// Start recording transactions to the unique_fd.
- // See BinderRecordReplay.h for more details.
+ // See RecordedTransaction.h for more details.
status_t startRecordingBinder(const android::base::unique_fd& fd);
// Stop the current recording.
status_t stopRecordingBinder();
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 2af512e..c78f870 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -198,7 +198,10 @@
{
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != nullptr) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
*outService = interface_cast<INTERFACE>(sm->getService(name));
+#pragma clang diagnostic pop // getService deprecation
if ((*outService) != nullptr) return NO_ERROR;
}
return NAME_NOT_FOUND;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index f730acb..162cd40 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -75,6 +75,7 @@
size_t dataAvail() const;
size_t dataPosition() const;
size_t dataCapacity() const;
+ size_t dataBufferSize() const;
status_t setDataSize(size_t size);
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
index 9896fd7..08d8e43 100644
--- a/libs/binder/include/binder/ParcelFileDescriptor.h
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -42,6 +42,7 @@
android::status_t writeToParcel(android::Parcel* parcel) const override;
android::status_t readFromParcel(const android::Parcel* parcel) override;
+ inline std::string toString() const { return "ParcelFileDescriptor:" + std::to_string(get()); }
inline bool operator!=(const ParcelFileDescriptor& rhs) const {
return mFd.get() != rhs.mFd.get();
}
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 88790a8..40fd30a 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -111,6 +111,11 @@
Stability getStability() const override { return mStability; }
+ inline std::string toString() const {
+ return "ParcelableHolder:" +
+ (mParcelableName ? std::string(String8(mParcelableName.value()).c_str())
+ : "<parceled>");
+ }
inline bool operator!=(const ParcelableHolder& rhs) const {
return this != &rhs;
}
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index bad8cb1..471c994 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -64,6 +64,11 @@
// For main functions - dangerous for libraries to use
status_t setThreadPoolMaxThreadCount(size_t maxThreads);
status_t enableOnewaySpamDetection(bool enable);
+
+ // Set the name of the current thread to look like a threadpool
+ // thread. Typically this is called before joinThreadPool.
+ //
+ // TODO: remove this API, and automatically set it intelligently.
void giveThreadPoolName();
String8 getDriverName();
diff --git a/libs/binder/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/RecordedTransaction.h
similarity index 72%
rename from libs/binder/include/binder/BinderRecordReplay.h
rename to libs/binder/include/binder/RecordedTransaction.h
index 25ed5e5..eb765fe 100644
--- a/libs/binder/include/binder/BinderRecordReplay.h
+++ b/libs/binder/include/binder/RecordedTransaction.h
@@ -26,25 +26,26 @@
// 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.
+// RecordedTransaction.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);
+ static std::optional<RecordedTransaction> fromDetails(const String16& interfaceName,
+ uint32_t code, uint32_t flags,
+ timespec timestamp, const Parcel& data,
+ const Parcel& reply, status_t err);
RecordedTransaction(RecordedTransaction&& t) noexcept;
[[nodiscard]] status_t dumpToFile(const android::base::unique_fd& fd) const;
+ const std::string& getInterfaceName() const;
uint32_t getCode() const;
uint32_t getFlags() const;
- uint64_t getDataSize() const;
- uint64_t getReplySize() const;
int32_t getReturnedStatus() const;
+ timespec getTimestamp() const;
uint32_t getVersion() const;
const Parcel& getDataParcel() const;
const Parcel& getReplyParcel() const;
@@ -52,27 +53,31 @@
private:
RecordedTransaction() = default;
+ android::status_t writeChunk(const android::base::borrowed_fd, uint32_t chunkType,
+ size_t byteCount, const uint8_t* data) const;
+
#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
+ int64_t timestampSeconds = 0;
+ int32_t timestampNanoseconds = 0;
+ int32_t reserved = 0;
};
#pragma clang diagnostic pop
static_assert(sizeof(TransactionHeader) == 32);
static_assert(sizeof(TransactionHeader) % 8 == 0);
- TransactionHeader mHeader;
+ struct MovableData { // movable
+ TransactionHeader mHeader;
+ std::string mInterfaceName;
+ };
+ MovableData mData;
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
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 78dae4b..e7943dd 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -112,6 +112,13 @@
LOG(ERROR) << "Failed to get fd for the socket:" << name;
return nullptr;
}
+ // Control socket fds are inherited from init, so they don't have O_CLOEXEC set.
+ // But we don't want any child processes to inherit the socket we are running
+ // the server on, so attempt to set the flag now.
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
+ LOG(WARNING) << "Failed to set CLOEXEC on control socket with name " << name
+ << " error: " << errno;
+ }
if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
<< " error: " << statusToString(status).c_str();
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
index 2a00736..b0c7f6d 100644
--- a/libs/binder/ndk/include_cpp/android/binder_to_string.h
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -49,12 +49,17 @@
#include <android/binder_interface_utils.h>
#include <android/binder_parcelable_utils.h>
#define HAS_NDK_INTERFACE
-#else
+#endif
+
+// TODO: some things include libbinder without having access to libbase. This is
+// due to frameworks/native/include, which symlinks to libbinder headers, so even
+// though we don't use it here, we detect a different header, so that we are more
+// confident libbase will be included
+#if __has_include(<binder/RpcSession.h>)
#include <binder/IBinder.h>
#include <binder/IInterface.h>
-#include <binder/ParcelFileDescriptor.h>
-#include <binder/ParcelableHolder.h>
-#endif //_has_include
+#define HAS_CPP_INTERFACE
+#endif
namespace android {
namespace internal {
@@ -104,10 +109,12 @@
IsInstantiationOf<_U, sp>::value || // for IBinder and interface types in the C++
// backend
#endif
- IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the
- // C++/NDK backends
- IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the
- // NDK backends
+ IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the
+ // C++/NDK backends
+ IsInstantiationOf<_U, std::unique_ptr>::value || // for @nullable(heap=true)
+ // in C++/NDK backends
+ IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the
+ // NDK backends
std::true_type>
_test(int);
@@ -132,36 +139,15 @@
};
template <typename _T>
-class ToEmptyString {
- template <typename _U>
- static std::enable_if_t<
-#ifdef HAS_NDK_INTERFACE
- std::is_base_of_v<::ndk::ICInterface, _U>
-#if __ANDROID_API__ >= 31
- || std::is_same_v<::ndk::AParcelableHolder, _U>
-#endif
-#else
- std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> ||
- std::is_same_v<os::ParcelFileDescriptor, _U> ||
- std::is_same_v<os::ParcelableHolder, _U>
-#endif
- ,
- std::true_type>
- _test(int);
- template <typename _U>
- static std::false_type _test(...);
-
- public:
- enum { value = decltype(_test<_T>(0))::value };
+struct TypeDependentFalse {
+ enum { value = false };
};
} // namespace details
template <typename _T>
std::string ToString(const _T& t) {
- if constexpr (details::ToEmptyString<_T>::value) {
- return "<unimplemented>";
- } else if constexpr (std::is_same_v<bool, _T>) {
+ if constexpr (std::is_same_v<bool, _T>) {
return t ? "true" : "false";
} else if constexpr (std::is_same_v<char16_t, _T>) {
// TODO(b/244494451): codecvt is deprecated in C++17 -- suppress the
@@ -181,6 +167,24 @@
return ss.str();
} else if constexpr (std::is_same_v<::ndk::ScopedFileDescriptor, _T>) {
return "fd:" + std::to_string(t.get());
+ } else if constexpr (std::is_base_of_v<::ndk::ICInterface, _T>) {
+ // TODO(b/266248339): this format is to make it easy to handle resolv_integration_test
+ // freezing the output format. We would like to print more info.
+ return "<interface>";
+#if __ANDROID_API__ >= 31
+ } else if constexpr (std::is_same_v<::ndk::AParcelableHolder, _T>) {
+ return "AParcelableHolder";
+#endif
+#endif // HAS_NDK_INTERFACE
+#ifdef HAS_CPP_INTERFACE
+ } else if constexpr (std::is_base_of_v<IInterface, _T>) {
+ std::stringstream ss;
+ ss << "interface:" << std::hex << &t;
+ return ss.str();
+ } else if constexpr (std::is_same_v<IBinder, _T>) {
+ std::stringstream ss;
+ ss << "binder:" << std::hex << &t;
+ return ss.str();
#endif
#ifdef HAS_STRING16
} else if constexpr (std::is_same_v<String16, _T>) {
@@ -214,11 +218,27 @@
out << "]";
return out.str();
} else {
- return "{no toString() implemented}";
+ static_assert(details::TypeDependentFalse<_T>::value, "no toString implemented, huh?");
}
}
} // namespace internal
} // namespace android
+#ifdef HAS_STRONG_POINTER
+#undef HAS_STRONG_POINTER
+#endif
+
+#ifdef HAS_STRING16
+#undef HAS_STRING16
+#endif
+
+#ifdef HAS_NDK_INTERFACE
+#undef HAS_NDK_INTERFACE
+#endif
+
+#ifdef HAS_CPP_INTERFACE
+#undef HAS_CPP_INTERFACE
+#endif
+
/** @} */
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 8693022..b5a2e2f 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -695,11 +695,17 @@
if (parcel->get()->objectsCount()) {
return STATUS_INVALID_OPERATION;
}
- int32_t dataSize = AParcel_getDataSize(parcel);
+ // b/264739302 - getDataSize will return dataPos if it is greater than dataSize
+ // which will cause crashes in memcpy at later point. Instead compare with
+ // actual length of internal buffer
+ int32_t dataSize = parcel->get()->dataBufferSize();
if (len > static_cast<size_t>(dataSize) || start > static_cast<size_t>(dataSize) - len) {
return STATUS_BAD_VALUE;
}
const uint8_t* internalBuffer = parcel->get()->data();
+ if (internalBuffer == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
memcpy(buffer, internalBuffer + start, len);
return STATUS_OK;
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index a0e61d9..0c8b48f 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -94,14 +94,12 @@
//! ```
#[macro_use]
-mod proxy;
-
-#[macro_use]
mod binder;
mod binder_async;
mod error;
mod native;
mod parcel;
+mod proxy;
mod state;
use binder_ndk_sys as sys;
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
index c5c7719..29bf92c 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -17,9 +17,6 @@
#![allow(missing_docs)]
#![no_main]
-#[macro_use]
-extern crate libfuzzer_sys;
-
mod read_utils;
use crate::read_utils::READ_FUNCS;
@@ -31,7 +28,7 @@
StatusCode,
};
use binder_random_parcel_rs::create_random_parcel;
-use libfuzzer_sys::arbitrary::Arbitrary;
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
#[derive(Arbitrary, Debug)]
enum ReadOperation {
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
index a427f28..c530382 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/service_fuzzer.rs
@@ -16,8 +16,8 @@
#![allow(missing_docs)]
#![no_main]
-#[macro_use]
-extern crate libfuzzer_sys;
+
+use libfuzzer_sys::fuzz_target;
use binder::{self, BinderFeatures, Interface};
use binder_random_parcel_rs::fuzz_service;
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 5db3187..7006f87 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -138,6 +138,7 @@
aidl_interface {
name: "binderRpcTestIface",
+ vendor_available: true,
host_supported: true,
unstable: true,
srcs: [
@@ -158,6 +159,7 @@
cc_library_static {
name: "libbinder_tls_test_utils",
+ vendor_available: true,
host_supported: true,
target: {
darwin: {
@@ -211,6 +213,7 @@
defaults: [
"binderRpcTest_common_defaults",
],
+ vendor_available: true,
gtest: false,
auto_gen_config: false,
srcs: [
@@ -221,10 +224,18 @@
cc_defaults {
name: "binderRpcTest_defaults",
+ vendor_available: true,
target: {
android: {
test_suites: ["vts"],
},
+
+ vendor: {
+ shared_libs: [
+ "libbinder_trusty",
+ "libtrusty",
+ ],
+ },
},
defaults: [
"binderRpcTest_common_defaults",
@@ -267,6 +278,7 @@
name: "binderRpcTest_static_defaults",
shared_libs: [
+ "liblog",
"libutils",
// libcrypto_static is not visible to this module
"libcrypto",
@@ -274,7 +286,6 @@
static_libs: [
"libbase",
"libcutils",
- "liblog",
"libssl",
],
@@ -336,6 +347,29 @@
],
}
+cc_binary {
+ name: "binderRpcTestService_on_trusty_mock",
+ defaults: [
+ "trusty_mock_defaults",
+ ],
+
+ srcs: [
+ "binderRpcTestCommon.cpp",
+ "binderRpcTestServiceTrusty.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder_on_trusty_mock",
+ "libbase",
+ "libutils",
+ "libcutils",
+ ],
+
+ static_libs: [
+ "binderRpcTestIface-cpp",
+ ],
+}
+
cc_test {
name: "binderRpcTest",
defaults: [
@@ -347,6 +381,7 @@
// Add the Trusty mock library as a fake dependency so it gets built
required: [
"libbinder_on_trusty_mock",
+ "binderRpcTestService_on_trusty_mock",
],
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index f7498c4..955c650 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1406,9 +1406,11 @@
ASSERT_TRUE(server != nullptr);
int32_t delay = 1000; // ms
data.writeInt32(delay);
+ // b/266537959 - must take before taking lock, since countdown is started in the remote
+ // process there.
+ size_t epochMsBefore = epochMillis();
EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK, data, &reply), NO_ERROR);
std::vector<std::thread> ts;
- size_t epochMsBefore = epochMillis();
for (size_t i = 0; i < kKernelThreads + 1; i++) {
ts.push_back(std::thread([&] {
Parcel local_reply;
diff --git a/libs/binder/tests/binderRecordedTransactionTest.cpp b/libs/binder/tests/binderRecordedTransactionTest.cpp
index 23864e6..30172cc 100644
--- a/libs/binder/tests/binderRecordedTransactionTest.cpp
+++ b/libs/binder/tests/binderRecordedTransactionTest.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include <binder/BinderRecordReplay.h>
+#include <binder/RecordedTransaction.h>
#include <gtest/gtest.h>
+#include <utils/Errors.h>
using android::Parcel;
using android::status_t;
@@ -23,12 +24,16 @@
using android::binder::debug::RecordedTransaction;
TEST(BinderRecordedTransaction, RoundTripEncoding) {
+ android::String16 interfaceName("SampleInterface");
Parcel d;
d.writeInt32(12);
d.writeInt64(2);
Parcel r;
r.writeInt32(99);
- auto transaction = RecordedTransaction::fromDetails(1, 42, d, r, 0);
+ timespec ts = {1232456, 567890};
+
+ auto transaction = RecordedTransaction::fromDetails(interfaceName, 1, 42, ts, d, r, 0);
+ EXPECT_TRUE(transaction.has_value());
auto file = std::tmpfile();
auto fd = unique_fd(fcntl(fileno(file), F_DUPFD, 1));
@@ -40,10 +45,13 @@
auto retrievedTransaction = RecordedTransaction::fromFile(fd);
+ EXPECT_EQ(retrievedTransaction->getInterfaceName(), android::String8(interfaceName).c_str());
EXPECT_EQ(retrievedTransaction->getCode(), 1);
EXPECT_EQ(retrievedTransaction->getFlags(), 42);
- EXPECT_EQ(retrievedTransaction->getDataSize(), 12);
- EXPECT_EQ(retrievedTransaction->getReplySize(), 4);
+ EXPECT_EQ(retrievedTransaction->getTimestamp().tv_sec, ts.tv_sec);
+ EXPECT_EQ(retrievedTransaction->getTimestamp().tv_nsec, ts.tv_nsec);
+ EXPECT_EQ(retrievedTransaction->getDataParcel().dataSize(), 12);
+ EXPECT_EQ(retrievedTransaction->getReplyParcel().dataSize(), 4);
EXPECT_EQ(retrievedTransaction->getReturnedStatus(), 0);
EXPECT_EQ(retrievedTransaction->getVersion(), 0);
@@ -51,3 +59,82 @@
EXPECT_EQ(retrievedTransaction->getDataParcel().readInt64(), 2);
EXPECT_EQ(retrievedTransaction->getReplyParcel().readInt32(), 99);
}
+
+TEST(BinderRecordedTransaction, Checksum) {
+ android::String16 interfaceName("SampleInterface");
+ Parcel d;
+ d.writeInt32(12);
+ d.writeInt64(2);
+ Parcel r;
+ r.writeInt32(99);
+ timespec ts = {1232456, 567890};
+ auto transaction = RecordedTransaction::fromDetails(interfaceName, 1, 42, ts, d, r, 0);
+
+ auto file = std::tmpfile();
+ auto fd = unique_fd(fcntl(fileno(file), F_DUPFD, 1));
+
+ status_t status = transaction->dumpToFile(fd);
+ ASSERT_EQ(android::NO_ERROR, status);
+
+ lseek(fd.get(), 9, SEEK_SET);
+ uint32_t badData = 0xffffffff;
+ write(fd.get(), &badData, sizeof(uint32_t));
+ std::rewind(file);
+
+ auto retrievedTransaction = RecordedTransaction::fromFile(fd);
+
+ EXPECT_FALSE(retrievedTransaction.has_value());
+}
+
+TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) {
+ // File contents are read with mmap.
+ // This test verifies that transactions are read from portions
+ // of files that cross page boundaries and don't start at a
+ // page boundary offset of the fd.
+ const size_t pageSize = sysconf(_SC_PAGE_SIZE);
+ const size_t largeDataSize = pageSize + 100;
+ std::vector<uint8_t> largePayload;
+ uint8_t filler = 0xaa;
+ largePayload.insert(largePayload.end(), largeDataSize, filler);
+ android::String16 interfaceName("SampleInterface");
+ Parcel d;
+ d.writeInt32(12);
+ d.writeInt64(2);
+ d.writeByteVector(largePayload);
+ Parcel r;
+ r.writeInt32(99);
+ timespec ts = {1232456, 567890};
+ auto transaction = RecordedTransaction::fromDetails(interfaceName, 1, 42, ts, d, r, 0);
+
+ auto file = std::tmpfile();
+ auto fd = unique_fd(fcntl(fileno(file), F_DUPFD, 1));
+
+ // Write to file twice
+ status_t status = transaction->dumpToFile(fd);
+ ASSERT_EQ(android::NO_ERROR, status);
+ status = transaction->dumpToFile(fd);
+ ASSERT_EQ(android::NO_ERROR, status);
+
+ std::rewind(file);
+
+ for (int i = 0; i < 2; i++) {
+ auto retrievedTransaction = RecordedTransaction::fromFile(fd);
+
+ EXPECT_EQ(retrievedTransaction->getCode(), 1);
+ EXPECT_EQ(retrievedTransaction->getFlags(), 42);
+ EXPECT_EQ(retrievedTransaction->getTimestamp().tv_sec, ts.tv_sec);
+ EXPECT_EQ(retrievedTransaction->getTimestamp().tv_nsec, ts.tv_nsec);
+ EXPECT_EQ(retrievedTransaction->getDataParcel().dataSize(), d.dataSize());
+ EXPECT_EQ(retrievedTransaction->getReplyParcel().dataSize(), 4);
+ EXPECT_EQ(retrievedTransaction->getReturnedStatus(), 0);
+ EXPECT_EQ(retrievedTransaction->getVersion(), 0);
+
+ EXPECT_EQ(retrievedTransaction->getDataParcel().readInt32(), 12);
+ EXPECT_EQ(retrievedTransaction->getDataParcel().readInt64(), 2);
+ std::optional<std::vector<uint8_t>> payloadOut;
+ EXPECT_EQ(retrievedTransaction->getDataParcel().readByteVector(&payloadOut), android::OK);
+ EXPECT_EQ(payloadOut.value(), largePayload);
+
+ EXPECT_EQ(retrievedTransaction->getReplyParcel().readInt32(), 99);
+ }
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 8afa49b..84c93dd 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <aidl/IBinderRpcTest.h>
#include <android-base/stringprintf.h>
#include <chrono>
@@ -27,6 +28,11 @@
#include <sys/prctl.h>
#include <sys/socket.h>
+#ifdef __ANDROID_VENDOR__
+#include <binder/RpcTransportTipcAndroid.h>
+#include <trusty/tipc.h>
+#endif // __ANDROID_VENDOR__
+
#include "binderRpcTestCommon.h"
#include "binderRpcTestFixture.h"
@@ -44,6 +50,10 @@
constexpr bool kEnableSharedLibs = true;
#endif
+#ifdef __ANDROID_VENDOR__
+constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0";
+#endif
+
static std::string WaitStatusToString(int wstatus) {
if (WIFEXITED(wstatus)) {
return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
@@ -269,6 +279,11 @@
auto ret = std::make_unique<LinuxProcessSession>(
Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) {
+ if (socketType == SocketType::TIPC) {
+ // Trusty has a single persistent service
+ return;
+ }
+
auto writeFd = std::to_string(writeEnd.get());
auto readFd = std::to_string(readEnd.get());
execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
@@ -287,31 +302,47 @@
serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
static_cast<int32_t>(mode));
}
- writeToFd(ret->host.writeEnd(), serverConfig);
+ if (socketType != SocketType::TIPC) {
+ writeToFd(ret->host.writeEnd(), serverConfig);
+ }
std::vector<sp<RpcSession>> sessions;
auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
for (size_t i = 0; i < options.numSessions; i++) {
- sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
+ std::unique_ptr<RpcTransportCtxFactory> factory;
+ if (socketType == SocketType::TIPC) {
+#ifdef __ANDROID_VENDOR__
+ factory = RpcTransportCtxFactoryTipcAndroid::make();
+#else
+ LOG_ALWAYS_FATAL("TIPC socket type only supported on vendor");
+#endif
+ } else {
+ factory = newFactory(rpcSecurity, certVerifier);
+ }
+ sessions.emplace_back(RpcSession::make(std::move(factory)));
}
- auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret->host.readEnd());
- BinderRpcTestClientInfo clientInfo;
- for (const auto& session : sessions) {
- auto& parcelableCert = clientInfo.certs.emplace_back();
- parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
- }
- writeToFd(ret->host.writeEnd(), clientInfo);
+ BinderRpcTestServerInfo serverInfo;
+ if (socketType != SocketType::TIPC) {
+ serverInfo = readFromFd<BinderRpcTestServerInfo>(ret->host.readEnd());
+ BinderRpcTestClientInfo clientInfo;
+ for (const auto& session : sessions) {
+ auto& parcelableCert = clientInfo.certs.emplace_back();
+ parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+ }
+ writeToFd(ret->host.writeEnd(), clientInfo);
- CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
- if (socketType == SocketType::INET) {
- CHECK_NE(0, serverInfo.port);
- }
+ CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
+ if (socketType == SocketType::INET) {
+ CHECK_NE(0, serverInfo.port);
+ }
- if (rpcSecurity == RpcSecurity::TLS) {
- const auto& serverCert = serverInfo.cert.data;
- CHECK_EQ(OK,
- certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM, serverCert));
+ if (rpcSecurity == RpcSecurity::TLS) {
+ const auto& serverCert = serverInfo.cert.data;
+ CHECK_EQ(OK,
+ certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ serverCert));
+ }
}
status_t status;
@@ -342,6 +373,19 @@
case SocketType::INET:
status = session->setupInetClient("127.0.0.1", serverInfo.port);
break;
+ case SocketType::TIPC:
+ status = session->setupPreconnectedClient({}, [=]() {
+#ifdef __ANDROID_VENDOR__
+ auto port = trustyIpcPort(serverVersion);
+ int tipcFd = tipc_connect(kTrustyIpcDevice, port.c_str());
+ return tipcFd >= 0 ? android::base::unique_fd(tipcFd)
+ : android::base::unique_fd();
+#else
+ LOG_ALWAYS_FATAL("Tried to connect to Trusty outside of vendor");
+ return android::base::unique_fd();
+#endif
+ });
+ break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
@@ -682,7 +726,11 @@
proc.expectAlreadyShutdown = true;
}
-TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) {
+TEST_P(BinderRpc, DeathRecipientFailsWithoutIncoming) {
+ if (socketType() == SocketType::TIPC) {
+ // This should work, but Trusty takes too long to restart the service
+ GTEST_SKIP() << "Service death test not supported on Trusty";
+ }
class MyDeathRec : public IBinder::DeathRecipient {
public:
void binderDied(const wp<IBinder>& /* who */) override {}
@@ -692,8 +740,7 @@
{.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0});
auto dr = sp<MyDeathRec>::make();
- EXPECT_DEATH(proc.rootBinder->linkToDeath(dr, (void*)1, 0),
- "Cannot register a DeathRecipient without any incoming connections.");
+ EXPECT_EQ(INVALID_OPERATION, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
}
TEST_P(BinderRpc, UnlinkDeathRecipient) {
@@ -725,6 +772,11 @@
}
TEST_P(BinderRpc, Die) {
+ if (socketType() == SocketType::TIPC) {
+ // This should work, but Trusty takes too long to restart the service
+ GTEST_SKIP() << "Service death test not supported on Trusty";
+ }
+
for (bool doDeathCleanup : {true, false}) {
auto proc = createRpcTestSocketServerProcess({});
@@ -777,6 +829,10 @@
}
TEST_P(BinderRpc, FileDescriptorTransportRejectNone) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
+
auto proc = createRpcTestSocketServerProcess({
.clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
.serverSupportedFileDescriptorTransportModes =
@@ -793,6 +849,10 @@
}
TEST_P(BinderRpc, FileDescriptorTransportRejectUnix) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
+
auto proc = createRpcTestSocketServerProcess({
.clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
.serverSupportedFileDescriptorTransportModes =
@@ -809,6 +869,10 @@
}
TEST_P(BinderRpc, FileDescriptorTransportOptionalUnix) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
+
auto proc = createRpcTestSocketServerProcess({
.clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE,
.serverSupportedFileDescriptorTransportModes =
@@ -822,6 +886,10 @@
}
TEST_P(BinderRpc, ReceiveFile) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
+
auto proc = createRpcTestSocketServerProcess({
.clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
.serverSupportedFileDescriptorTransportModes =
@@ -842,6 +910,10 @@
}
TEST_P(BinderRpc, SendFiles) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
+
auto proc = createRpcTestSocketServerProcess({
.clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
.serverSupportedFileDescriptorTransportModes =
@@ -914,6 +986,10 @@
}
TEST_P(BinderRpc, AppendInvalidFd) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
+
auto proc = createRpcTestSocketServerProcess({
.clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
.serverSupportedFileDescriptorTransportModes =
@@ -940,6 +1016,7 @@
ASSERT_EQ(-1, pRaw.readFileDescriptor());
}
+#ifndef __ANDROID_VENDOR__ // No AIBinder_fromPlatformBinder on vendor
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
if constexpr (!kEnableSharedLibs) {
GTEST_SKIP() << "Test disabled because Binder was built as a static library";
@@ -971,6 +1048,7 @@
ASSERT_TRUE(status.isOk()) << status.getDescription();
ASSERT_EQ("aoeuaoeu", out);
}
+#endif // __ANDROID_VENDOR__
ssize_t countFds() {
DIR* dir = opendir("/proc/self/fd/");
@@ -986,6 +1064,9 @@
if (serverSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
}
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "File descriptor tests not supported on Trusty (yet)";
+ }
ssize_t beforeFds = countFds();
ASSERT_GE(beforeFds, 0);
@@ -1100,13 +1181,19 @@
return ret;
}
-static std::vector<uint32_t> testVersions() {
- std::vector<uint32_t> versions;
- for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) {
- versions.push_back(i);
+static std::vector<SocketType> testTipcSocketTypes() {
+#ifdef __ANDROID_VENDOR__
+ auto port = trustyIpcPort(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+ int tipcFd = tipc_connect(kTrustyIpcDevice, port.c_str());
+ if (tipcFd >= 0) {
+ close(tipcFd);
+ return {SocketType::TIPC};
}
- versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
- return versions;
+#endif // __ANDROID_VENDOR__
+
+ // TIPC is not supported on this device, most likely
+ // because /dev/trusty-ipc-dev0 is missing
+ return {};
}
INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
@@ -1118,6 +1205,14 @@
::testing::Values(false, true)),
BinderRpc::PrintParamInfo);
+INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
+ ::testing::Combine(::testing::ValuesIn(testTipcSocketTypes()),
+ ::testing::Values(RpcSecurity::RAW),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::ValuesIn(testVersions()),
+ ::testing::Values(true), ::testing::Values(true)),
+ BinderRpc::PrintParamInfo);
+
class BinderRpcServerRootObject
: public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
@@ -1369,7 +1464,10 @@
addr, port);
return base::unique_fd{};
};
- }
+ } break;
+ case SocketType::TIPC: {
+ LOG_ALWAYS_FATAL("RpcTransportTest should not be enabled for TIPC");
+ } break;
}
mFd = rpcServer->releaseServer();
if (!mFd.fd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
diff --git a/libs/binder/tests/binderRpcTestCommon.cpp b/libs/binder/tests/binderRpcTestCommon.cpp
index 0d9aa95..fe9a5a1 100644
--- a/libs/binder/tests/binderRpcTestCommon.cpp
+++ b/libs/binder/tests/binderRpcTestCommon.cpp
@@ -19,6 +19,6 @@
namespace android {
std::atomic<int32_t> MyBinderRpcSession::gNum;
-sp<IBinder> MyBinderRpcTest::mHeldBinder;
+sp<IBinder> MyBinderRpcTestBase::mHeldBinder;
} // namespace android
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 654e16c..a467ee3 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -22,37 +22,42 @@
#include <BnBinderRpcCallback.h>
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
-#include <aidl/IBinderRpcTest.h>
+#include <android-base/stringprintf.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <unistd.h>
+#include <cinttypes>
+#include <string>
+#include <vector>
+
+#ifndef __TRUSTY__
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
-#include <binder/Binder.h>
-#include <binder/BpBinder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-#include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
-#include <binder/RpcThreads.h>
#include <binder/RpcTlsTestUtils.h>
#include <binder/RpcTlsUtils.h>
-#include <binder/RpcTransport.h>
-#include <binder/RpcTransportRaw.h>
#include <binder/RpcTransportTls.h>
-#include <unistd.h>
-#include <string>
-#include <vector>
#include <signal.h>
-#include "../BuildFlags.h"
-#include "../FdTrigger.h"
#include "../OS.h" // for testing UnixBootstrap clients
#include "../RpcSocketAddress.h" // for testing preconnected clients
-#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
+#endif // __TRUSTY__
+
+#include "../BuildFlags.h"
+#include "../FdTrigger.h"
+#include "../RpcState.h" // for debugging
#include "utils/Errors.h"
namespace android {
@@ -65,6 +70,19 @@
return {RpcSecurity::RAW, RpcSecurity::TLS};
}
+static inline std::vector<uint32_t> testVersions() {
+ std::vector<uint32_t> versions;
+ for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) {
+ versions.push_back(i);
+ }
+ versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+ return versions;
+}
+
+static inline std::string trustyIpcPort(uint32_t serverVersion) {
+ return base::StringPrintf("com.android.trusty.binderRpcTestService.V%" PRIu32, serverVersion);
+}
+
enum class SocketType {
PRECONNECTED,
UNIX,
@@ -72,6 +90,7 @@
UNIX_RAW,
VSOCK,
INET,
+ TIPC,
};
static inline std::string PrintToString(SocketType socketType) {
@@ -88,6 +107,8 @@
return "vm_socket";
case SocketType::INET:
return "inet_socket";
+ case SocketType::TIPC:
+ return "trusty_ipc";
default:
LOG_ALWAYS_FATAL("Unknown socket type");
return "";
@@ -118,6 +139,7 @@
bool allowConnectFailure = false;
};
+#ifndef __TRUSTY__
static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
uint64_t length = str.length();
CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
@@ -182,6 +204,7 @@
}).detach();
return readFd;
}
+#endif // __TRUSTY__
// A threadsafe channel where writes block until the value is read.
template <typename T>
@@ -252,9 +275,12 @@
std::vector<std::string> mValues;
};
-class MyBinderRpcTest : public BnBinderRpcTest {
+// Base class for all concrete implementations of MyBinderRpcTest.
+// Sub-classes that want to provide a full implementation should derive
+// from this class instead of MyBinderRpcTestDefault below so the compiler
+// checks that all methods are implemented.
+class MyBinderRpcTestBase : public BnBinderRpcTest {
public:
- wp<RpcServer> server;
int port = 0;
Status sendString(const std::string& str) override {
@@ -269,18 +295,6 @@
*out = port;
return Status::ok();
}
- Status countBinders(std::vector<int32_t>* out) override {
- sp<RpcServer> spServer = server.promote();
- if (spServer == nullptr) {
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
- }
- out->clear();
- for (auto session : spServer->listSessions()) {
- size_t count = session->state()->countBinders();
- out->push_back(count);
- }
- return Status::ok();
- }
Status getNullBinder(sp<IBinder>* out) override {
out->clear();
return Status::ok();
@@ -381,62 +395,55 @@
return doCallback(callback, oneway, delayed, value);
}
- Status die(bool cleanup) override {
- if (cleanup) {
- exit(1);
- } else {
- _exit(1);
- }
- }
-
- Status scheduleShutdown() override {
- sp<RpcServer> strongServer = server.promote();
- if (strongServer == nullptr) {
+protected:
+ // Generic version of countBinders that works with both
+ // RpcServer and RpcServerTrusty
+ template <typename T>
+ Status countBindersImpl(const wp<T>& server, std::vector<int32_t>* out) {
+ sp<T> spServer = server.promote();
+ if (spServer == nullptr) {
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
- RpcMaybeThread([=] {
- LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
- }).detach();
- return Status::ok();
- }
-
- Status useKernelBinderCallingId() override {
- // this is WRONG! It does not make sense when using RPC binder, and
- // because it is SO wrong, and so much code calls this, it should abort!
-
- if constexpr (kEnableKernelIpc) {
- (void)IPCThreadState::self()->getCallingPid();
+ out->clear();
+ for (auto session : spServer->listSessions()) {
+ size_t count = session->state()->countBinders();
+ out->push_back(count);
}
return Status::ok();
}
+};
- Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
- out->reset(mockFileDescriptor(content));
- return Status::ok();
+// Default implementation of MyBinderRpcTest that can be used as-is
+// or derived from by classes that only want to implement a subset of
+// the unimplemented methods
+class MyBinderRpcTestDefault : public MyBinderRpcTestBase {
+public:
+ Status countBinders(std::vector<int32_t>* /*out*/) override {
+ return Status::fromStatusT(UNKNOWN_TRANSACTION);
}
- Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
- android::os::ParcelFileDescriptor* out) override {
- std::string acc;
- for (const auto& file : files) {
- std::string result;
- CHECK(android::base::ReadFdToString(file.get(), &result));
- acc.append(result);
- }
- out->reset(mockFileDescriptor(acc));
- return Status::ok();
+ Status die(bool /*cleanup*/) override { return Status::fromStatusT(UNKNOWN_TRANSACTION); }
+
+ Status scheduleShutdown() override { return Status::fromStatusT(UNKNOWN_TRANSACTION); }
+
+ Status useKernelBinderCallingId() override { return Status::fromStatusT(UNKNOWN_TRANSACTION); }
+
+ Status echoAsFile(const std::string& /*content*/,
+ android::os::ParcelFileDescriptor* /*out*/) override {
+ return Status::fromStatusT(UNKNOWN_TRANSACTION);
}
- HandoffChannel<android::base::unique_fd> mFdChannel;
-
- Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override {
- mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0)));
- return Status::ok();
+ Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& /*files*/,
+ android::os::ParcelFileDescriptor* /*out*/) override {
+ return Status::fromStatusT(UNKNOWN_TRANSACTION);
}
- Status blockingRecvFd(android::os::ParcelFileDescriptor* fd) override {
- fd->reset(mFdChannel.read());
- return Status::ok();
+ Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& /*fd*/) override {
+ return Status::fromStatusT(UNKNOWN_TRANSACTION);
+ }
+
+ Status blockingRecvFd(android::os::ParcelFileDescriptor* /*fd*/) override {
+ return Status::fromStatusT(UNKNOWN_TRANSACTION);
}
};
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 5a78782..c99d68a 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -106,6 +106,10 @@
// Whether the test params support sending FDs in parcels.
bool supportsFdTransport() const {
+ if (socketType() == SocketType::TIPC) {
+ // Trusty does not support file descriptors yet
+ return false;
+ }
return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS &&
(socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX ||
socketType() == SocketType::UNIX_BOOTSTRAP ||
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index cc9726b..714f063 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -18,6 +18,73 @@
using namespace android;
+class MyBinderRpcTestAndroid : public MyBinderRpcTestBase {
+public:
+ wp<RpcServer> server;
+
+ Status countBinders(std::vector<int32_t>* out) override {
+ return countBindersImpl(server, out);
+ }
+
+ Status die(bool cleanup) override {
+ if (cleanup) {
+ exit(1);
+ } else {
+ _exit(1);
+ }
+ }
+
+ Status scheduleShutdown() override {
+ sp<RpcServer> strongServer = server.promote();
+ if (strongServer == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ RpcMaybeThread([=] {
+ LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
+ }).detach();
+ return Status::ok();
+ }
+
+ Status useKernelBinderCallingId() override {
+ // this is WRONG! It does not make sense when using RPC binder, and
+ // because it is SO wrong, and so much code calls this, it should abort!
+
+ if constexpr (kEnableKernelIpc) {
+ (void)IPCThreadState::self()->getCallingPid();
+ }
+ return Status::ok();
+ }
+
+ Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
+ out->reset(mockFileDescriptor(content));
+ return Status::ok();
+ }
+
+ Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
+ android::os::ParcelFileDescriptor* out) override {
+ std::string acc;
+ for (const auto& file : files) {
+ std::string result;
+ CHECK(android::base::ReadFdToString(file.get(), &result));
+ acc.append(result);
+ }
+ out->reset(mockFileDescriptor(acc));
+ return Status::ok();
+ }
+
+ HandoffChannel<android::base::unique_fd> mFdChannel;
+
+ Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override {
+ mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0)));
+ return Status::ok();
+ }
+
+ Status blockingRecvFd(android::os::ParcelFileDescriptor* fd) override {
+ fd->reset(mFdChannel.read());
+ return Status::ok();
+ }
+};
+
int main(int argc, const char* argv[]) {
LOG_ALWAYS_FATAL_IF(argc != 3, "Invalid number of arguments: %d", argc);
base::unique_fd writeEnd(atoi(argv[1]));
@@ -88,7 +155,7 @@
// sizeof(sa_family_t)==2 in addrlen
CHECK_GE(len, sizeof(sa_family_t));
const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
- sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
+ sp<MyBinderRpcTestAndroid> service = sp<MyBinderRpcTestAndroid>::make();
switch (addr->sa_family) {
case AF_UNIX:
// nothing to save
diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp
new file mode 100644
index 0000000..8557389
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestServiceTrusty.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#define TLOG_TAG "binderRpcTestService"
+
+#include <android-base/stringprintf.h>
+#include <binder/RpcServerTrusty.h>
+#include <inttypes.h>
+#include <lib/tipc/tipc.h>
+#include <lk/err_ptr.h>
+#include <stdio.h>
+#include <trusty_log.h>
+#include <vector>
+
+#include "binderRpcTestCommon.h"
+
+using namespace android;
+using android::base::StringPrintf;
+using binder::Status;
+
+static int gConnectionCounter = 0;
+
+class MyBinderRpcTestTrusty : public MyBinderRpcTestDefault {
+public:
+ wp<RpcServerTrusty> server;
+
+ Status countBinders(std::vector<int32_t>* out) override {
+ return countBindersImpl(server, out);
+ }
+
+ Status scheduleShutdown() override {
+ // TODO: Trusty does not support shutting down the tipc event loop,
+ // so we just terminate the service app since it is marked
+ // restart_on_exit
+ exit(EXIT_SUCCESS);
+ }
+
+ // TODO(b/242940548): implement echoAsFile and concatFiles
+};
+
+struct ServerInfo {
+ std::unique_ptr<std::string> port;
+ sp<RpcServerTrusty> server;
+};
+
+int main(void) {
+ TLOGI("Starting service\n");
+
+ tipc_hset* hset = tipc_hset_create();
+ if (IS_ERR(hset)) {
+ TLOGE("Failed to create handle set (%d)\n", PTR_ERR(hset));
+ return EXIT_FAILURE;
+ }
+
+ const auto port_acl = RpcServerTrusty::PortAcl{
+ .flags = IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT,
+ };
+
+ std::vector<ServerInfo> servers;
+ for (auto serverVersion : testVersions()) {
+ ServerInfo serverInfo{
+ .port = std::make_unique<std::string>(trustyIpcPort(serverVersion)),
+ };
+ TLOGI("Adding service port '%s'\n", serverInfo.port->c_str());
+
+ // Message size needs to be large enough to cover all messages sent by the
+ // tests: SendAndGetResultBackBig sends two large strings.
+ constexpr size_t max_msg_size = 4096;
+ auto serverOrErr =
+ RpcServerTrusty::make(hset, serverInfo.port->c_str(),
+ std::shared_ptr<const RpcServerTrusty::PortAcl>(&port_acl),
+ max_msg_size);
+ if (!serverOrErr.ok()) {
+ TLOGE("Failed to create RpcServer (%d)\n", serverOrErr.error());
+ return EXIT_FAILURE;
+ }
+
+ auto server = std::move(*serverOrErr);
+ serverInfo.server = server;
+ serverInfo.server->setProtocolVersion(serverVersion);
+ serverInfo.server->setPerSessionRootObject([=](const void* /*addrPtr*/, size_t /*len*/) {
+ auto service = sp<MyBinderRpcTestTrusty>::make();
+ // Assign a unique connection identifier to service->port so
+ // getClientPort returns a unique value per connection
+ service->port = ++gConnectionCounter;
+ service->server = server;
+ return service;
+ });
+
+ servers.push_back(std::move(serverInfo));
+ }
+
+ return tipc_run_event_loop(hset);
+}
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index f960442..2249e5c 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -113,6 +113,10 @@
}
TEST_P(BinderRpc, AppendSeparateFormats) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "Trusty does not support multiple server processes";
+ }
+
auto proc1 = createRpcTestSocketServerProcess({});
auto proc2 = createRpcTestSocketServerProcess({});
@@ -155,7 +159,9 @@
TEST_P(BinderRpc, SendAndGetResultBackBig) {
auto proc = createRpcTestSocketServerProcess({});
- std::string single = std::string(1024, 'a');
+ // Trusty has a limit of 4096 bytes for the entire RPC Binder message
+ size_t singleLen = socketType() == SocketType::TIPC ? 512 : 4096;
+ std::string single = std::string(singleLen, 'a');
std::string doubled;
EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
EXPECT_EQ(single + single, doubled);
@@ -259,6 +265,10 @@
// aren't supported.
TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
+ if (socketType() == SocketType::TIPC) {
+ GTEST_SKIP() << "Trusty does not support multiple server processes";
+ }
+
auto proc1 = createRpcTestSocketServerProcess({});
auto proc2 = createRpcTestSocketServerProcess({});
@@ -319,15 +329,19 @@
}
TEST_P(BinderRpc, NestedTransactions) {
+ auto fileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX;
+ if (socketType() == SocketType::TIPC) {
+ // TIPC does not support file descriptors yet
+ fileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::NONE;
+ }
auto proc = createRpcTestSocketServerProcess({
// Enable FD support because it uses more stack space and so represents
// something closer to a worst case scenario.
- .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
- .serverSupportedFileDescriptorTransportModes =
- {RpcSession::FileDescriptorTransportMode::UNIX},
+ .clientFileDescriptorTransportMode = fileDescriptorTransportMode,
+ .serverSupportedFileDescriptorTransportModes = {fileDescriptorTransportMode},
});
- auto nastyNester = sp<MyBinderRpcTest>::make();
+ auto nastyNester = sp<MyBinderRpcTestDefault>::make();
EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
wp<IBinder> weak = nastyNester;
diff --git a/libs/binder/tests/binderUtilsHostTest.cpp b/libs/binder/tests/binderUtilsHostTest.cpp
index 4330e3e..25e286c 100644
--- a/libs/binder/tests/binderUtilsHostTest.cpp
+++ b/libs/binder/tests/binderUtilsHostTest.cpp
@@ -37,17 +37,24 @@
EXPECT_EQ(result->stdoutStr, "foo\n");
}
+template <typename T>
+auto millisSince(std::chrono::time_point<T> now) {
+ auto elapsed = std::chrono::system_clock::now() - now;
+ return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+}
+
TEST(UtilsHost, ExecuteLongRunning) {
- auto now = std::chrono::system_clock::now();
+ auto start = std::chrono::system_clock::now();
{
- std::vector<std::string> args{"sh", "-c",
- "sleep 0.5 && echo -n f && sleep 0.5 && echo oo && sleep 1"};
- auto result = execute(std::move(args), [](const CommandResult& commandResult) {
+ std::vector<std::string>
+ args{"sh", "-c", "sleep 0.5 && echo -n f && sleep 0.5 && echo oo && sleep 100"};
+ auto result = execute(std::move(args), [&](const CommandResult& commandResult) {
+ std::cout << millisSince(start)
+ << "ms: GOT PARTIAL COMMAND RESULT:" << commandResult.stdoutStr << std::endl;
return android::base::EndsWith(commandResult.stdoutStr, "\n");
});
- auto elapsed = std::chrono::system_clock::now() - now;
- auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+ auto elapsedMs = millisSince(start);
EXPECT_GE(elapsedMs, 1000);
EXPECT_LT(elapsedMs, 2000);
@@ -58,22 +65,21 @@
// ~CommandResult() called, child process is killed.
// Assert that the second sleep does not finish.
- auto elapsed = std::chrono::system_clock::now() - now;
- auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
- EXPECT_LT(elapsedMs, 2000);
+ EXPECT_LT(millisSince(start), 2000);
}
TEST(UtilsHost, ExecuteLongRunning2) {
- auto now = std::chrono::system_clock::now();
+ auto start = std::chrono::system_clock::now();
{
std::vector<std::string> args{"sh", "-c",
- "sleep 2 && echo -n f && sleep 2 && echo oo && sleep 2"};
- auto result = execute(std::move(args), [](const CommandResult& commandResult) {
+ "sleep 2 && echo -n f && sleep 2 && echo oo && sleep 100"};
+ auto result = execute(std::move(args), [&](const CommandResult& commandResult) {
+ std::cout << millisSince(start)
+ << "ms: GOT PARTIAL COMMAND RESULT:" << commandResult.stdoutStr << std::endl;
return android::base::EndsWith(commandResult.stdoutStr, "\n");
});
- auto elapsed = std::chrono::system_clock::now() - now;
- auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+ auto elapsedMs = millisSince(start);
EXPECT_GE(elapsedMs, 4000);
EXPECT_LT(elapsedMs, 6000);
@@ -84,9 +90,7 @@
// ~CommandResult() called, child process is killed.
// Assert that the second sleep does not finish.
- auto elapsed = std::chrono::system_clock::now() - now;
- auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
- EXPECT_LT(elapsedMs, 6000);
+ EXPECT_LT(millisSince(start), 6000);
}
TEST(UtilsHost, KillWithSigKill) {
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 53e7de4..08eb27a 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -199,5 +199,25 @@
binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
FUZZ_LOG() << "status: " << status;
},
+ [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
+ FUZZ_LOG() << "about to marshal AParcel";
+ size_t start = provider.ConsumeIntegral<size_t>();
+ // limit 1MB to avoid OOM issues
+ size_t len = provider.ConsumeIntegralInRange<size_t>(0, 1000000);
+ uint8_t buffer[len];
+ binder_status_t status = AParcel_marshal(p.aParcel(), buffer, start, len);
+ FUZZ_LOG() << "status: " << status;
+ },
+ [](const NdkParcelAdapter& /*p*/, FuzzedDataProvider& provider) {
+ FUZZ_LOG() << "about to unmarshal AParcel";
+ size_t len = provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes());
+ std::vector<uint8_t> parcelData = provider.ConsumeBytes<uint8_t>(len);
+ const uint8_t* buffer = parcelData.data();
+ const size_t bufferLen = parcelData.size();
+ NdkParcelAdapter adapter;
+ binder_status_t status = AParcel_unmarshal(adapter.aParcel(), buffer, bufferLen);
+ FUZZ_LOG() << "status: " << status;
+ },
+
};
// clang-format on
diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp
index 18ce316..109da75 100644
--- a/libs/binder/trusty/RpcServerTrusty.cpp
+++ b/libs/binder/trusty/RpcServerTrusty.cpp
@@ -117,7 +117,15 @@
*ctx_p = channelContext;
};
- base::unique_fd clientFd(chan);
+ // We need to duplicate the channel handle here because the tipc library
+ // owns the original handle and closes is automatically on channel cleanup.
+ // We use dup() because Trusty does not have fcntl().
+ // NOLINTNEXTLINE(android-cloexec-dup)
+ handle_t chanDup = dup(chan);
+ if (chanDup < 0) {
+ return chanDup;
+ }
+ base::unique_fd clientFd(chanDup);
android::RpcTransportFd transportFd(std::move(clientFd));
std::array<uint8_t, RpcServer::kRpcAddressSize> addr;
diff --git a/libs/binder/trusty/binderRpcTest/aidl/rules.mk b/libs/binder/trusty/binderRpcTest/aidl/rules.mk
new file mode 100644
index 0000000..1afd324
--- /dev/null
+++ b/libs/binder/trusty/binderRpcTest/aidl/rules.mk
@@ -0,0 +1,30 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_TESTS_DIR := frameworks/native/libs/binder/tests
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_AIDLS := \
+ $(LIBBINDER_TESTS_DIR)/BinderRpcTestClientInfo.aidl \
+ $(LIBBINDER_TESTS_DIR)/BinderRpcTestServerConfig.aidl \
+ $(LIBBINDER_TESTS_DIR)/BinderRpcTestServerInfo.aidl \
+ $(LIBBINDER_TESTS_DIR)/IBinderRpcCallback.aidl \
+ $(LIBBINDER_TESTS_DIR)/IBinderRpcSession.aidl \
+ $(LIBBINDER_TESTS_DIR)/IBinderRpcTest.aidl \
+ $(LIBBINDER_TESTS_DIR)/ParcelableCertificateData.aidl \
+
+include make/aidl.mk
diff --git a/libs/binder/trusty/binderRpcTest/service/manifest.json b/libs/binder/trusty/binderRpcTest/service/manifest.json
new file mode 100644
index 0000000..1c4f7ee
--- /dev/null
+++ b/libs/binder/trusty/binderRpcTest/service/manifest.json
@@ -0,0 +1,10 @@
+{
+ "uuid": "87e424e5-69d7-4bbd-8b7c-7e24812cbc94",
+ "app_name": "binderRpcTestService",
+ "min_heap": 65536,
+ "min_stack": 16384,
+ "mgmt_flags": {
+ "restart_on_exit": true,
+ "non_critical_app": true
+ }
+}
diff --git a/libs/binder/trusty/binderRpcTest/service/rules.mk b/libs/binder/trusty/binderRpcTest/service/rules.mk
new file mode 100644
index 0000000..5d1a51d
--- /dev/null
+++ b/libs/binder/trusty/binderRpcTest/service/rules.mk
@@ -0,0 +1,33 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_TESTS_DIR := frameworks/native/libs/binder/tests
+
+MODULE := $(LOCAL_DIR)
+
+MANIFEST := $(LOCAL_DIR)/manifest.json
+
+MODULE_SRCS := \
+ $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \
+ $(LIBBINDER_TESTS_DIR)/binderRpcTestServiceTrusty.cpp \
+
+MODULE_LIBRARY_DEPS := \
+ frameworks/native/libs/binder/trusty \
+ frameworks/native/libs/binder/trusty/binderRpcTest/aidl \
+ trusty/user/base/lib/libstdc++-trusty \
+ trusty/user/base/lib/tipc \
+
+include make/trusted_app.mk
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index 7d9dd8c..6678eb8 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -71,6 +71,11 @@
}
sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); }
+ /**
+ * For debugging!
+ */
+ std::vector<sp<RpcSession>> listSessions() { return mRpcServer->listSessions(); }
+
private:
// Both this class and RpcServer have multiple non-copyable fields,
// including mPortAcl below which can't be copied because mUuidPtrs
diff --git a/libs/binder/trusty/include_mock/lib/tipc/tipc.h b/libs/binder/trusty/include_mock/lib/tipc/tipc.h
new file mode 100644
index 0000000..ead9f9c
--- /dev/null
+++ b/libs/binder/trusty/include_mock/lib/tipc/tipc.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct tipc_hset;
+
+struct tipc_hset* tipc_hset_create(void) {
+ return nullptr;
+}
+int tipc_run_event_loop(struct tipc_hset*) {
+ return 0;
+}
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/libs/binder/trusty/include_mock/lk/err_ptr.h b/libs/binder/trusty/include_mock/lk/err_ptr.h
new file mode 100644
index 0000000..ab3fbba
--- /dev/null
+++ b/libs/binder/trusty/include_mock/lk/err_ptr.h
@@ -0,0 +1,19 @@
+/*
+ * 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
+
+#define IS_ERR(x) (!(x))
+#define PTR_ERR(x) (!!(x))
diff --git a/libs/binder/trusty/include_mock/trusty_ipc.h b/libs/binder/trusty/include_mock/trusty_ipc.h
index a2170ce..43ab84a 100644
--- a/libs/binder/trusty/include_mock/trusty_ipc.h
+++ b/libs/binder/trusty/include_mock/trusty_ipc.h
@@ -24,6 +24,9 @@
#define INFINITE_TIME 1
#define IPC_MAX_MSG_HANDLES 8
+#define IPC_PORT_ALLOW_TA_CONNECT 0x1
+#define IPC_PORT_ALLOW_NS_CONNECT 0x2
+
#define IPC_HANDLE_POLL_HUP 0x1
#define IPC_HANDLE_POLL_MSG 0x2
#define IPC_HANDLE_POLL_SEND_UNBLOCKED 0x4
diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk
index 4e5cd18..42db29a 100644
--- a/libs/binder/trusty/rules.mk
+++ b/libs/binder/trusty/rules.mk
@@ -79,6 +79,11 @@
-DBINDER_RPC_SINGLE_THREADED \
-D__ANDROID_VNDK__ \
+# libbinder has some deprecated declarations that we want to produce warnings
+# not errors
+MODULE_EXPORT_COMPILEFLAGS += \
+ -Wno-error=deprecated-declarations \
+
MODULE_LIBRARY_DEPS += \
trusty/user/base/lib/libstdc++-trusty \
trusty/user/base/lib/tipc \
diff --git a/libs/binder/trusty/usertests-inc.mk b/libs/binder/trusty/usertests-inc.mk
new file mode 100644
index 0000000..2f5a7f4
--- /dev/null
+++ b/libs/binder/trusty/usertests-inc.mk
@@ -0,0 +1,17 @@
+# 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.
+#
+
+TRUSTY_USER_TESTS += \
+ frameworks/native/libs/binder/trusty/binderRpcTest/service \
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index b2e8bea..85a5249 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -311,6 +311,16 @@
*/
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
+ /**
+ * Usage: The buffer is used for front-buffer rendering. When
+ * front-buffering rendering is specified, different usages may adjust their
+ * behavior as a result. For example, when used as GPU_COLOR_OUTPUT the buffer
+ * will behave similar to a single-buffered window. When used with
+ * COMPOSER_OVERLAY, the system will try to prioritize the buffer receiving
+ * an overlay plane & avoid caching it in intermediate composition buffers.
+ */
+ AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1UL << 32,
+
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
AHARDWAREBUFFER_USAGE_VENDOR_2 = 1ULL << 30,
diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h
index 906d9c6..9fea21e 100644
--- a/libs/nativewindow/include/android/hardware_buffer_aidl.h
+++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h
@@ -83,7 +83,7 @@
class HardwareBuffer {
public:
HardwareBuffer() noexcept {}
- explicit HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {}
+ HardwareBuffer(HardwareBuffer&& other) noexcept : mBuffer(other.release()) {}
~HardwareBuffer() {
reset();
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index a98e697..f582423 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -109,6 +109,11 @@
return NO_ERROR;
}
+status_t GraphicBufferMapper::importBufferNoValidate(const native_handle_t* rawHandle,
+ buffer_handle_t* outHandle) {
+ return mMapper->importBuffer(rawHandle, outHandle);
+}
+
void GraphicBufferMapper::getTransportSize(buffer_handle_t handle,
uint32_t* outTransportNumFds, uint32_t* outTransportNumInts)
{
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 507fa35..37a2e1c 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -59,6 +59,8 @@
PixelFormat format, uint64_t usage, uint32_t stride,
buffer_handle_t* outHandle);
+ status_t importBufferNoValidate(const native_handle_t* rawHandle, buffer_handle_t* outHandle);
+
status_t freeBuffer(buffer_handle_t handle);
void getTransportSize(buffer_handle_t handle,
diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp
index 0a4873c..3fb33b4 100644
--- a/libs/ui/tests/colorspace_test.cpp
+++ b/libs/ui/tests/colorspace_test.cpp
@@ -111,6 +111,7 @@
EXPECT_NEAR(1.0f, sRGB.getEOTF()(1.0f), 1e-6f);
EXPECT_NEAR(1.0f, sRGB.getOETF()(1.0f), 1e-6f);
+ // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
for (float v = 0.0f; v <= 0.5f; v += 1e-3f) {
ASSERT_TRUE(v >= sRGB.getEOTF()(v));
ASSERT_TRUE(v <= sRGB.getOETF()(v));
@@ -118,6 +119,7 @@
float previousEOTF = std::numeric_limits<float>::lowest();
float previousOETF = std::numeric_limits<float>::lowest();
+ // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
for (float v = 0.0f; v <= 1.0f; v += 1e-3f) {
ASSERT_TRUE(previousEOTF < sRGB.getEOTF()(v));
previousEOTF = sRGB.getEOTF()(v);
@@ -131,6 +133,7 @@
{0.3127f, 0.3290f}
// linear transfer functions
);
+ // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c)
for (float v = 0.0f; v <= 1.0f; v += 1e-3f) {
ASSERT_EQ(v, sRGB2.getEOTF()(v));
ASSERT_EQ(v, sRGB2.getOETF()(v));
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index 72bd292..614a78e 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -53,4 +53,6 @@
vintf_fragments: [
"manifest_android.frameworks.automotive.display@1.0.xml",
],
+
+ system_ext_specific: true,
}
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
index 5c7f344..ea1077a 100644
--- a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -1,4 +1,4 @@
-service automotive_display /system/bin/android.frameworks.automotive.display@1.0-service
+service automotive_display /system_ext/bin/android.frameworks.automotive.display@1.0-service
class hal
user graphics
group automotive_evs
diff --git a/services/batteryservice/include/batteryservice/BatteryService.h b/services/batteryservice/include/batteryservice/BatteryService.h
index 178bc29..a2e4115 100644
--- a/services/batteryservice/include/batteryservice/BatteryService.h
+++ b/services/batteryservice/include/batteryservice/BatteryService.h
@@ -34,6 +34,9 @@
BATTERY_PROP_CAPACITY = 4, // equals BATTERY_PROPERTY_CAPACITY
BATTERY_PROP_ENERGY_COUNTER = 5, // equals BATTERY_PROPERTY_ENERGY_COUNTER
BATTERY_PROP_BATTERY_STATUS = 6, // equals BATTERY_PROPERTY_BATTERY_STATUS
+ BATTERY_PROP_CHARGING_POLICY = 7, // equals BATTERY_PROPERTY_CHARGING_POLICY
+ BATTERY_PROP_MANUFACTURING_DATE = 8, // equals BATTERY_PROPERTY_MANUFACTURING_DATE
+ BATTERY_PROP_FIRST_USAGE_DATE = 9, // equals BATTERY_PROPERTY_FIRST_USAGE_DATE
};
struct BatteryProperties {
diff --git a/services/batteryservice/include/batteryservice/BatteryServiceConstants.h b/services/batteryservice/include/batteryservice/BatteryServiceConstants.h
index 8a90a12..2d7072d 100644
--- a/services/batteryservice/include/batteryservice/BatteryServiceConstants.h
+++ b/services/batteryservice/include/batteryservice/BatteryServiceConstants.h
@@ -1,7 +1,5 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-
-#ifndef HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
-#define HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
+#ifndef AIDL_android_hardware_health_V2_EXPORTED_CONSTANTS_H_
+#define AIDL_android_hardware_health_V2_EXPORTED_CONSTANTS_H_
#ifdef __cplusplus
extern "C" {
@@ -15,6 +13,8 @@
BATTERY_STATUS_FULL = 5,
};
+// must be kept in sync with definitions in
+// hardware/interfaces/health/aidl/android/hardware/health/BatteryHealth.aidl
enum {
BATTERY_HEALTH_UNKNOWN = 1,
BATTERY_HEALTH_GOOD = 2,
@@ -23,10 +23,23 @@
BATTERY_HEALTH_OVER_VOLTAGE = 5,
BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6,
BATTERY_HEALTH_COLD = 7,
+ BATTERY_HEALTH_FAIR = 8,
+ BATTERY_HEALTH_NOT_AVAILABLE = 11,
+ BATTERY_HEALTH_INCONSISTENT = 12,
+};
+
+// must be kept in sync with definitions in
+// hardware/interfaces/health/aidl/android/hardware/health/BatteryChargingState.aidl
+enum {
+ BATTERY_STATUS_NORMAL = 1,
+ BATTERY_STATUS_TOO_COLD = 2,
+ BATTERY_STATUS_TOO_HOT = 3,
+ BATTERY_STATUS_LONG_LIFE = 4,
+ BATTERY_STATUS_ADAPTIVE = 5,
};
#ifdef __cplusplus
}
#endif
-#endif // HIDL_GENERATED_android_hardware_health_V1_0_EXPORTED_CONSTANTS_H_
+#endif // AIDL_android_hardware_health_V2_EXPORTED_CONSTANTS_H_
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c52e96d..8364ed9 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -826,25 +826,24 @@
mHdrMetadata.cta8613.maxFrameAverageLightLevel}});
}
- Error error = static_cast<Error>(
- mComposer.setLayerPerFrameMetadata(mDisplay->getId(), mId, perFrameMetadatas));
+ const Error error = static_cast<Error>(
+ mComposer.setLayerPerFrameMetadata(mDisplay->getId(), mId, perFrameMetadatas));
+ if (error != Error::NONE) {
+ return error;
+ }
+ std::vector<Hwc2::PerFrameMetadataBlob> perFrameMetadataBlobs;
if (validTypes & HdrMetadata::HDR10PLUS) {
if (CC_UNLIKELY(mHdrMetadata.hdr10plus.size() == 0)) {
return Error::BAD_PARAMETER;
}
- std::vector<Hwc2::PerFrameMetadataBlob> perFrameMetadataBlobs;
perFrameMetadataBlobs.push_back(
{Hwc2::PerFrameMetadataKey::HDR10_PLUS_SEI, mHdrMetadata.hdr10plus});
- Error setMetadataBlobsError =
- static_cast<Error>(mComposer.setLayerPerFrameMetadataBlobs(mDisplay->getId(), mId,
- perFrameMetadataBlobs));
- if (error == Error::NONE) {
- return setMetadataBlobsError;
- }
}
- return error;
+
+ return static_cast<Error>(
+ mComposer.setLayerPerFrameMetadataBlobs(mDisplay->getId(), mId, perFrameMetadataBlobs));
}
Error Layer::setDisplayFrame(const Rect& frame)
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index a2305af..3611dea 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -314,12 +314,12 @@
virtual void parseArgs(const Vector<String16>& args, std::string& result) = 0;
// Sets the max number of display frames that can be stored. Called by SF backdoor.
- virtual void setMaxDisplayFrames(uint32_t size);
+ virtual void setMaxDisplayFrames(uint32_t size) = 0;
// Computes the historical fps for the provided set of layer IDs
// The fps is compted from the linear timeline of present timestamps for DisplayFrames
// containing at least one layer ID.
- virtual float computeFps(const std::unordered_set<int32_t>& layerIds);
+ virtual float computeFps(const std::unordered_set<int32_t>& layerIds) = 0;
// Restores the max number of display frames to default. Called by SF backdoor.
virtual void reset() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e228468..76c7b9e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2138,8 +2138,16 @@
bool needsTraversal = false;
if (clearTransactionFlags(eTransactionFlushNeeded)) {
+ // Locking:
+ // 1. to prevent onHandleDestroyed from being called while the state lock is held,
+ // we must keep a copy of the transactions (specifically the composer
+ // states) around outside the scope of the lock
+ // 2. Transactions and created layers do not share a lock. To prevent applying
+ // transactions with layers still in the createdLayer queue, flush the transactions
+ // before committing the created layers.
+ std::vector<TransactionState> transactions = flushTransactions();
needsTraversal |= commitCreatedLayers();
- needsTraversal |= flushTransactionQueues(vsyncId);
+ needsTraversal |= applyTransactions(transactions, vsyncId);
}
const bool shouldCommit =
@@ -3798,7 +3806,7 @@
return transactionsPendingBarrier;
}
-bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
+std::vector<TransactionState> SurfaceFlinger::flushTransactions() {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
@@ -3892,14 +3900,25 @@
flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
applyTokensWithUnsignaledTransactions);
}
-
- return applyTransactions(transactions, vsyncId);
}
}
+ return transactions;
+}
+
+// for test only
+bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
+ std::vector<TransactionState> transactions = flushTransactions();
+ return applyTransactions(transactions, vsyncId);
}
bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
int64_t vsyncId) {
+ Mutex::Autolock _l(mStateLock);
+ return applyTransactionsLocked(transactions, vsyncId);
+}
+
+bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions,
+ int64_t vsyncId) {
bool needsTraversal = false;
// Now apply all transactions.
for (auto& transaction : transactions) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 02846fe..0f711af 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -770,6 +770,9 @@
REQUIRES(mStateLock);
// flush pending transaction that was presented after desiredPresentTime.
bool flushTransactionQueues(int64_t vsyncId);
+
+ std::vector<TransactionState> flushTransactions();
+
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
@@ -818,7 +821,8 @@
size_t totalTXapplied) const;
bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
applyTokensWithUnsignaledTransactions) const;
- bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
+ bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
+ bool applyTransactionsLocked(std::vector<TransactionState>& transactions, int64_t vsyncId)
REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)