Merge "RpcBinder: Add AF_UNIX socketpair transport"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 6fb9a4d..48d48ac 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -193,8 +193,9 @@
{ OPT, "events/ext4/ext4_da_write_end/enable" },
{ OPT, "events/ext4/ext4_sync_file_enter/enable" },
{ OPT, "events/ext4/ext4_sync_file_exit/enable" },
- { REQ, "events/block/block_rq_issue/enable" },
- { REQ, "events/block/block_rq_complete/enable" },
+ { OPT, "events/block/block_bio_queue/enable" },
+ { OPT, "events/block/block_bio_complete/enable" },
+ { OPT, "events/ufs/ufshcd_command/enable" },
} },
{ "mmc", "eMMC commands", 0, {
{ REQ, "events/mmc/enable" },
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4f1020c..6e9747f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1028,7 +1028,7 @@
MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
return;
}
- RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
+ RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
// Use a different name from "incident.proto"
@@ -1066,7 +1066,7 @@
return;
}
RunCommandToFd(fd, "", {"cmd", "window", "dump-visible-window-views"},
- CommandOptions::WithTimeout(120).Build());
+ CommandOptions::WithTimeout(10).Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
if (!empty) {
ds.AddZipEntry("visible_windows.zip", path);
@@ -1405,7 +1405,9 @@
// Dump all of the files that make up the vendor interface.
// See the files listed in dumpFileList() for the latest list of files.
static void DumpVintf() {
- const auto vintfFiles = android::vintf::details::dumpFileList();
+
+ const std::string sku = android::base::GetProperty("ro.boot.product.hardware.sku", "");
+ const auto vintfFiles = android::vintf::details::dumpFileList(sku);
for (const auto vintfFile : vintfFiles) {
struct stat st;
if (stat(vintfFile.c_str(), &st) == 0) {
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index e978e79..6a3120c 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -27,6 +27,7 @@
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/wait.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -504,6 +505,11 @@
return 0;
}
+ if (WIFSIGNALED(dexopt_result)) {
+ LOG(WARNING) << "Interrupted by signal " << WTERMSIG(dexopt_result) ;
+ return dexopt_result;
+ }
+
// If this was a profile-guided run, we may have profile version issues. Try to downgrade,
// if possible.
if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) {
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index a99ccae..3681d5b 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -49,14 +49,14 @@
#ifdef __ANDROID_RECOVERY__
auto vintfObject = vintf::VintfObjectRecovery::GetInstance();
if (vintfObject == nullptr) {
- LOG(ERROR) << "NULL VintfObjectRecovery!";
+ ALOGE("NULL VintfObjectRecovery!");
return {};
}
return {ManifestWithDescription{vintfObject->getRecoveryHalManifest(), "recovery"}};
#else
auto vintfObject = vintf::VintfObject::GetInstance();
if (vintfObject == nullptr) {
- LOG(ERROR) << "NULL VintfObject!";
+ ALOGE("NULL VintfObject!");
return {};
}
return {ManifestWithDescription{vintfObject->getDeviceHalManifest(), "device"},
@@ -68,10 +68,10 @@
static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) {
for (const ManifestWithDescription& mwd : GetManifestsWithDescription()) {
if (mwd.manifest == nullptr) {
- LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
- // note, we explicitly do not retry here, so that we can detect VINTF
- // or other bugs (b/151696835)
- continue;
+ ALOGE("NULL VINTF MANIFEST!: %s", mwd.description);
+ // note, we explicitly do not retry here, so that we can detect VINTF
+ // or other bugs (b/151696835)
+ continue;
}
if (func(mwd)) return true;
}
@@ -87,8 +87,9 @@
size_t firstSlash = name.find('/');
size_t lastDot = name.rfind('.', firstSlash);
if (firstSlash == std::string::npos || lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. "
- << "some.package.foo.IFoo/default) but got: " << name;
+ ALOGE("VINTF HALs require names in the format type/instance (e.g. "
+ "some.package.foo.IFoo/default) but got: %s",
+ name.c_str());
return false;
}
aname->package = name.substr(0, lastDot);
@@ -104,7 +105,7 @@
bool found = forEachManifest([&](const ManifestWithDescription& mwd) {
if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) {
- LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
+ ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description);
return true; // break
}
return false; // continue
@@ -113,8 +114,8 @@
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(INFO) << "Could not find " << aname.package << "." << aname.iface << "/"
- << aname.instance << " in the VINTF manifest.";
+ ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(),
+ aname.iface.c_str(), aname.instance.c_str());
}
return found;
@@ -173,7 +174,9 @@
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
- LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface;
+ ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) "
+ "but got: %s",
+ interface.c_str());
return {};
}
const std::string package = interface.substr(0, lastDot);
@@ -308,7 +311,7 @@
}
if (!isValidServiceName(name)) {
- LOG(ERROR) << "Invalid service name: " << name;
+ ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
}
@@ -322,7 +325,7 @@
// implicitly unlinked when the binder is removed
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
- LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
@@ -335,21 +338,20 @@
// only trying to detect when two different services are accidentally installed.
if (existing.ctx.uid != ctx.uid) {
- LOG(WARNING) << "Service '" << name << "' originally registered from UID "
- << existing.ctx.uid << " but it is now being registered from UID "
- << ctx.uid << ". Multiple instances installed?";
+ ALOGW("Service '%s' originally registered from UID %u but it is now being registered "
+ "from UID %u. Multiple instances installed?",
+ name.c_str(), existing.ctx.uid, ctx.uid);
}
if (existing.ctx.sid != ctx.sid) {
- LOG(WARNING) << "Service '" << name << "' originally registered from SID "
- << existing.ctx.sid << " but it is now being registered from SID "
- << ctx.sid << ". Multiple instances installed?";
+ ALOGW("Service '%s' originally registered from SID %s but it is now being registered "
+ "from SID %s. Multiple instances installed?",
+ name.c_str(), existing.ctx.sid.c_str(), ctx.sid.c_str());
}
- LOG(INFO) << "Service '" << name << "' originally registered from PID "
- << existing.ctx.debugPid << " but it is being registered again from PID "
- << ctx.debugPid
- << ". Bad state? Late death notification? Multiple instances installed?";
+ ALOGI("Service '%s' originally registered from PID %d but it is being registered again "
+ "from PID %d. Bad state? Late death notification? Multiple instances installed?",
+ name.c_str(), existing.ctx.debugPid, ctx.debugPid);
}
// Overwrite the old service if it exists
@@ -406,7 +408,7 @@
}
if (!isValidServiceName(name)) {
- LOG(ERROR) << "Invalid service name: " << name;
+ ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
@@ -417,7 +419,7 @@
if (OK !=
IInterface::asBinder(callback)->linkToDeath(
sp<ServiceManager>::fromExisting(this))) {
- LOG(ERROR) << "Could not linkToDeath when adding " << name;
+ ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -449,7 +451,7 @@
}
if (!found) {
- LOG(ERROR) << "Trying to unregister callback, but none exists " << name;
+ ALOGE("Trying to unregister callback, but none exists %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -571,10 +573,11 @@
std::thread([=] {
if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
- LOG(INFO) << "Tried to start aidl service " << name
- << " as a lazy service, but was unable to. Usually this happens when a "
- "service is not installed, but if the service is intended to be used as a "
- "lazy service, then it may be configured incorrectly.";
+ ALOGI("Tried to start aidl service %s as a lazy service, but was unable to. Usually "
+ "this happens when a "
+ "service is not installed, but if the service is intended to be used as a "
+ "lazy service, then it may be configured incorrectly.",
+ name.c_str());
}
}).detach();
}
@@ -592,24 +595,25 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- LOG(ERROR) << "Could not add callback for nonexistent service: " << name;
+ ALOGE("Could not add callback for nonexistent service: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
- LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")";
+ ALOGW("Only a server can register for client callbacks (for %s)", name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
if (serviceIt->second.binder != service) {
- LOG(WARNING) << "Tried to register client callback for " << name
- << " but a different service is registered under this name.";
+ ALOGW("Tried to register client callback for %s but a different service is registered "
+ "under this name.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
if (OK !=
IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
- LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name;
+ ALOGE("Could not linkToDeath when adding client callback for %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -694,7 +698,7 @@
void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end()) {
- LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName;
+ ALOGW("sendClientCallbackNotifications could not find service %s", serviceName.c_str());
return;
}
Service& service = serviceIt->second;
@@ -702,7 +706,7 @@
CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients
<< " so we can't tell clients again that we have client: " << hasClients;
- LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients;
+ ALOGI("Notifying %s they have clients: %d", serviceName.c_str(), hasClients);
auto ccIt = mNameToClientCallback.find(serviceName);
CHECK(ccIt != mNameToClientCallback.end())
@@ -727,26 +731,26 @@
auto serviceIt = mNameToService.find(name);
if (serviceIt == mNameToService.end()) {
- LOG(WARNING) << "Tried to unregister " << name
- << ", but that service wasn't registered to begin with.";
+ ALOGW("Tried to unregister %s, but that service wasn't registered to begin with.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) {
- LOG(WARNING) << "Only a server can unregister itself (for " << name << ")";
+ ALOGW("Only a server can unregister itself (for %s)", name.c_str());
return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
}
sp<IBinder> storedBinder = serviceIt->second.binder;
if (binder != storedBinder) {
- LOG(WARNING) << "Tried to unregister " << name
- << ", but a different service is registered under this name.";
+ ALOGW("Tried to unregister %s, but a different service is registered under this name.",
+ name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
if (serviceIt->second.guaranteeClient) {
- LOG(INFO) << "Tried to unregister " << name << ", but there is about to be a client.";
+ ALOGI("Tried to unregister %s, but there is about to be a client.", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -759,7 +763,7 @@
// So, if clients > 2, then at least one other service on the system must hold a refcount.
if (clients < 0 || clients > 2) {
// client callbacks are either disabled or there are other clients
- LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients;
+ ALOGI("Tried to unregister %s, but there are clients: %d", name.c_str(), clients);
// Set this flag to ensure the clients are acknowledged in the next callback
serviceIt->second.guaranteeClient = true;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 15bd5c3..ebc74fb 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -23,8 +23,10 @@
#include <sys/eventfd.h>
#include <sys/uio.h>
+#include <atomic>
#include <chrono>
#include <deque>
+#include <optional>
#include <string>
#include <string_view>
#include <tuple>
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 481d704..5e725a9 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -232,7 +232,10 @@
: mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
virtual ~RpcServerLink();
void binderDied(const wp<IBinder>&) override {
- LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
+ auto promoted = mBinder.promote();
+ ALOGI("RpcBinder: binder died, shutting down RpcServer for %s",
+ promoted ? String8(promoted->getInterfaceDescriptor()).c_str() : "<NULL>");
+
if (mRpcServer == nullptr) {
ALOGW("RpcServerLink: Unable to shut down RpcServer because it does not exist.");
} else {
@@ -241,11 +244,7 @@
}
mRpcServer.clear();
- auto promoted = mBinder.promote();
- if (promoted == nullptr) {
- ALOGW("RpcServerLink: Unable to remove link from parent binder object because parent "
- "binder object is gone.");
- } else {
+ if (promoted) {
promoted->removeRpcServerLink(sp<RpcServerLink>::fromExisting(this));
}
mBinder.clear();
@@ -706,6 +705,7 @@
return status;
}
rpcServer->setMaxThreads(binderThreadPoolMaxCount);
+ LOG(INFO) << "RpcBinder: Started Binder debug on " << getInterfaceDescriptor();
rpcServer->start();
e->mRpcServerLinks.emplace(link);
LOG_RPC_DETAIL("%s(fd=%d) successful", __PRETTY_FUNCTION__, socketFdForPrint);
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index bfcf39a..11c8e5d 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -39,7 +39,6 @@
#include <sys/resource.h>
#include <unistd.h>
-#include "Static.h"
#include "binder_module.h"
#if LOG_NDEBUG
@@ -124,46 +123,43 @@
return "unknown";
}
-static const void* printBinderTransactionData(TextOutput& out, const void* data)
-{
+static const void* printBinderTransactionData(std::ostream& out, const void* data) {
const binder_transaction_data* btd =
(const binder_transaction_data*)data;
if (btd->target.handle < 1024) {
/* want to print descriptors in decimal; guess based on value */
- out << "target.desc=" << btd->target.handle;
+ out << "\ttarget.desc=" << btd->target.handle;
} else {
- out << "target.ptr=" << btd->target.ptr;
+ out << "\ttarget.ptr=" << btd->target.ptr;
}
- out << " (cookie " << btd->cookie << ")" << endl
- << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << endl
- << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
- << " bytes)" << endl
- << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
- << " bytes)";
+ out << "\t (cookie " << btd->cookie << ")"
+ << "\n"
+ << "\tcode=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << "\n"
+ << "\tdata=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)"
+ << "\n"
+ << "\toffsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size << " bytes)";
return btd+1;
}
-static const void* printReturnCommand(TextOutput& out, const void* _cmd)
-{
+static const void* printReturnCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
uint32_t code = (uint32_t)*cmd++;
size_t cmdIndex = code & 0xff;
if (code == BR_ERROR) {
- out << "BR_ERROR: " << (void*)(uint64_t)(*cmd++) << endl;
+ out << "\tBR_ERROR: " << (void*)(uint64_t)(*cmd++) << "\n";
return cmd;
} else if (cmdIndex >= N) {
- out << "Unknown reply: " << code << endl;
+ out << "\tUnknown reply: " << code << "\n";
return cmd;
}
- out << kReturnStrings[cmdIndex];
+ out << "\t" << kReturnStrings[cmdIndex];
switch (code) {
case BR_TRANSACTION:
case BR_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
+ out << ": ";
+ cmd = (const int32_t*)printBinderTransactionData(out, cmd);
} break;
case BR_ACQUIRE_RESULT: {
@@ -200,19 +196,18 @@
break;
}
- out << endl;
+ out << "\n";
return cmd;
}
-static const void* printCommand(TextOutput& out, const void* _cmd)
-{
+static const void* printCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
uint32_t code = (uint32_t)*cmd++;
size_t cmdIndex = code & 0xff;
if (cmdIndex >= N) {
- out << "Unknown command: " << code << endl;
+ out << "Unknown command: " << code << "\n";
return cmd;
}
out << kCommandStrings[cmdIndex];
@@ -220,9 +215,8 @@
switch (code) {
case BC_TRANSACTION:
case BC_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
+ out << ": ";
+ cmd = (const int32_t*)printBinderTransactionData(out, cmd);
} break;
case BC_ACQUIRE_RESULT: {
@@ -274,7 +268,7 @@
break;
}
- out << endl;
+ out << "\n";
return cmd;
}
@@ -548,8 +542,10 @@
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
- alog << "Processing top-level Command: "
- << getReturnString(cmd) << endl;
+ std::ostringstream logStream;
+ logStream << "Processing top-level Command: " << getReturnString(cmd) << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
pthread_mutex_lock(&mProcess->mThreadCountLock);
@@ -726,10 +722,11 @@
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
- << handle << " / code " << TypeCode(code) << ": "
- << indent << data << dedent << endl;
+ std::ostringstream logStream;
+ logStream << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand " << handle
+ << " / code " << TypeCode(code) << ": \t" << data << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
@@ -774,11 +771,15 @@
#endif
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
- << handle << ": ";
- if (reply) alog << indent << *reply << dedent << endl;
- else alog << "(none requested)" << endl;
+ std::ostringstream logStream;
+ logStream << "BR_REPLY thr " << (void*)pthread_self() << " / hand " << handle << ": ";
+ if (reply)
+ logStream << "\t" << *reply << "\n";
+ else
+ logStream << "(none requested)"
+ << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
} else {
err = waitForResponse(nullptr, nullptr);
@@ -920,8 +921,10 @@
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
- alog << "Processing waitForResponse Command: "
- << getReturnString(cmd) << endl;
+ std::ostringstream logStream;
+ logStream << "Processing waitForResponse Command: " << getReturnString(cmd) << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
switch (cmd) {
@@ -1033,17 +1036,19 @@
}
IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
+ std::ostringstream logStream;
if (outAvail != 0) {
- alog << "Sending commands to driver: " << indent;
+ logStream << "Sending commands to driver: ";
const void* cmds = (const void*)bwr.write_buffer;
- const void* end = ((const uint8_t*)cmds)+bwr.write_size;
- alog << HexDump(cmds, bwr.write_size) << endl;
- while (cmds < end) cmds = printCommand(alog, cmds);
- alog << dedent;
+ const void* end = ((const uint8_t*)cmds) + bwr.write_size;
+ logStream << "\t" << HexDump(cmds, bwr.write_size) << "\n";
+ while (cmds < end) cmds = printCommand(logStream, cmds);
}
- alog << "Size of receive buffer: " << bwr.read_size
- << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
+ logStream << "Size of receive buffer: " << bwr.read_size << ", needRead: " << needRead
+ << ", doReceive: " << doReceive << "\n";
+
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
// Return immediately if there is nothing to do.
@@ -1054,7 +1059,10 @@
status_t err;
do {
IF_LOG_COMMANDS() {
- alog << "About to read/write, write size = " << mOut.dataSize() << endl;
+ std::ostringstream logStream;
+ logStream << "About to read/write, write size = " << mOut.dataSize() << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
@@ -1068,14 +1076,20 @@
err = -EBADF;
}
IF_LOG_COMMANDS() {
- alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
+ std::ostringstream logStream;
+ logStream << "Finished read/write, write size = " << mOut.dataSize() << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
- alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
- << bwr.write_consumed << " (of " << mOut.dataSize()
- << "), read consumed: " << bwr.read_consumed << endl;
+ std::ostringstream logStream;
+ logStream << "Our err: " << (void*)(intptr_t)err
+ << ", write consumed: " << bwr.write_consumed << " (of " << mOut.dataSize()
+ << "), read consumed: " << bwr.read_consumed << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
if (err >= NO_ERROR) {
@@ -1096,14 +1110,15 @@
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
- alog << "Remaining data size: " << mOut.dataSize() << endl;
- alog << "Received commands from driver: " << indent;
+ std::ostringstream logStream;
+ logStream << "Remaining data size: " << mOut.dataSize() << "\n";
+ logStream << "Received commands from driver: ";
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
- alog << HexDump(cmds, mIn.dataSize()) << endl;
- while (cmds < end) cmds = printReturnCommand(alog, cmds);
- alog << dedent;
+ logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n";
+ while (cmds < end) cmds = printReturnCommand(logStream, cmds);
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
return NO_ERROR;
}
@@ -1285,15 +1300,15 @@
Parcel reply;
status_t error;
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_TRANSACTION thr " << (void*)pthread_self()
- << " / obj " << tr.target.ptr << " / code "
- << TypeCode(tr.code) << ": " << indent << buffer
- << dedent << endl
- << "Data addr = "
- << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
- << ", offsets addr="
- << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
+ std::ostringstream logStream;
+ logStream << "BR_TRANSACTION thr " << (void*)pthread_self() << " / obj "
+ << tr.target.ptr << " / code " << TypeCode(tr.code) << ": \t" << buffer
+ << "\n"
+ << "Data addr = " << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
+ << ", offsets addr="
+ << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
@@ -1329,21 +1344,21 @@
sendReply(reply, (tr.flags & kForwardReplyFlags));
} else {
if (error != OK) {
- alog << "oneway function results for code " << tr.code
- << " on binder at "
- << reinterpret_cast<void*>(tr.target.ptr)
- << " will be dropped but finished with status "
- << statusToString(error);
+ std::ostringstream logStream;
+ logStream << "oneway function results for code " << tr.code << " on binder at "
+ << reinterpret_cast<void*>(tr.target.ptr)
+ << " will be dropped but finished with status "
+ << statusToString(error);
// ideally we could log this even when error == OK, but it
// causes too much logspam because some manually-written
// interfaces have clients that call methods which always
// write results, sometimes as oneway methods.
if (reply.dataSize() != 0) {
- alog << " and reply parcel size " << reply.dataSize();
+ logStream << " and reply parcel size " << reply.dataSize();
}
-
- alog << endl;
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
@@ -1358,9 +1373,11 @@
mPropagateWorkSource = origPropagateWorkSet;
IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
- << tr.target.ptr << ": " << indent << reply << dedent << endl;
+ std::ostringstream logStream;
+ logStream << "BC_REPLY thr " << (void*)pthread_self() << " / obj " << tr.target.ptr
+ << ": \t" << reply << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
}
@@ -1481,7 +1498,10 @@
const binder_size_t* /*objects*/, size_t /*objectsSize*/) {
//ALOGI("Freeing parcel %p", &parcel);
IF_LOG_COMMANDS() {
- alog << "Writing BC_FREE_BUFFER for " << data << endl;
+ std::ostringstream logStream;
+ logStream << "Writing BC_FREE_BUFFER for " << data << "\n";
+ std::string message = logStream.str();
+ ALOGI("%s", message.c_str());
}
ALOG_ASSERT(data != NULL, "Called with NULL data");
IPCThreadState* state = self();
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 8887572..07d0a65 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1439,7 +1439,8 @@
case RpcSession::FileDescriptorTransportMode::NONE: {
return FDS_NOT_ALLOWED;
}
- case RpcSession::FileDescriptorTransportMode::UNIX: {
+ case RpcSession::FileDescriptorTransportMode::UNIX:
+ case RpcSession::FileDescriptorTransportMode::TRUSTY: {
if (rpcFields->mFds == nullptr) {
rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>();
}
@@ -2639,8 +2640,7 @@
return OK;
}
-void Parcel::print(TextOutput& to, uint32_t /*flags*/) const
-{
+void Parcel::print(std::ostream& to, uint32_t /*flags*/) const {
to << "Parcel(";
if (errorCheck() != NO_ERROR) {
@@ -2648,7 +2648,7 @@
to << "Error: " << (void*)(intptr_t)err << " \"" << strerror(-err) << "\"";
} else if (dataSize() > 0) {
const uint8_t* DATA = data();
- to << indent << HexDump(DATA, dataSize()) << dedent;
+ to << "\t" << HexDump(DATA, dataSize());
#ifdef BINDER_WITH_KERNEL_IPC
if (const auto* kernelFields = maybeKernelFields()) {
const binder_size_t* OBJS = kernelFields->mObjects;
@@ -2656,8 +2656,7 @@
for (size_t i = 0; i < N; i++) {
const flat_binder_object* flat =
reinterpret_cast<const flat_binder_object*>(DATA + OBJS[i]);
- to << endl
- << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+ to << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
<< TypeCode(flat->hdr.type & 0x7f7f7f00) << " = " << flat->binder;
}
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index c0e36c4..b27f102 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -41,7 +41,7 @@
#if RPC_FLAKE_PRONE
void rpcMaybeWaitToFlake() {
[[clang::no_destroy]] static std::random_device r;
- [[clang::no_destroy]] static std::mutex m;
+ [[clang::no_destroy]] static RpcMutex m;
unsigned num;
{
RpcMutexLockGuard lock(m);
@@ -56,6 +56,7 @@
case RpcSession::FileDescriptorTransportMode::NONE:
return false;
case RpcSession::FileDescriptorTransportMode::UNIX:
+ case RpcSession::FileDescriptorTransportMode::TRUSTY:
return true;
}
}
@@ -886,6 +887,7 @@
it->second.asyncTodo.push(BinderNode::AsyncTodo{
.ref = target,
.data = std::move(transactionData),
+ .ancillaryFds = std::move(ancillaryFds),
.asyncNumber = transaction->asyncNumber,
});
@@ -1046,6 +1048,7 @@
// reset up arguments
transactionData = std::move(todo.data);
+ ancillaryFds = std::move(todo.ancillaryFds);
LOG_ALWAYS_FATAL_IF(target != todo.ref,
"async list should be associated with a binder");
@@ -1205,6 +1208,20 @@
rpcFields->mFds->size(), kMaxFdsPerMsg);
return BAD_VALUE;
}
+ break;
+ }
+ case RpcSession::FileDescriptorTransportMode::TRUSTY: {
+ // Keep this in sync with trusty_ipc.h!!!
+ // We could import that file here on Trusty, but it's not
+ // available on Android
+ constexpr size_t kMaxFdsPerMsg = 8;
+ if (rpcFields->mFds->size() > kMaxFdsPerMsg) {
+ *errorMsg = StringPrintf("Too many file descriptors in Parcel for Trusty "
+ "IPC connection: %zu (max is %zu)",
+ rpcFields->mFds->size(), kMaxFdsPerMsg);
+ return BAD_VALUE;
+ }
+ break;
}
}
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 7aab5ee..ac86585 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -250,6 +250,7 @@
struct AsyncTodo {
sp<IBinder> ref;
CommandData data;
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>> ancillaryFds;
uint64_t asyncNumber = 0;
bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index c91d56c..342e4a3 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -58,13 +58,10 @@
"name": "CtsOsTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "include-filter": "android.os.cts.BinderTest"
},
{
- "exclude-filter": "android.os.cts.BuildTest#testSdkInt"
- },
- {
- "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
+ "include-filter": "android.os.cts.ParcelTest"
}
]
},
diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp
index a0ade50..5dd1f90 100644
--- a/libs/binder/TextOutput.cpp
+++ b/libs/binder/TextOutput.cpp
@@ -39,11 +39,10 @@
static void textOutputPrinter(void* cookie, const char* txt)
{
- ((TextOutput*)cookie)->print(txt, strlen(txt));
+ ((std::ostream*)cookie)->write(txt, strlen(txt));
}
-TextOutput& operator<<(TextOutput& to, const TypeCode& val)
-{
+std::ostream& operator<<(std::ostream& to, const TypeCode& val) {
printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to);
return to;
}
@@ -61,8 +60,7 @@
else mAlignment = 1;
}
-TextOutput& operator<<(TextOutput& to, const HexDump& val)
-{
+std::ostream& operator<<(std::ostream& to, const HexDump& val) {
printHexData(0, val.buffer(), val.size(), val.bytesPerLine(),
val.singleLineCutoff(), val.alignment(), val.carrayStyle(),
textOutputPrinter, (void*)&to);
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5469239..6de6ce8 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -595,7 +595,7 @@
// uid.
uid_t readCallingWorkSourceUid() const;
- void print(TextOutput& to, uint32_t flags = 0) const;
+ void print(std::ostream& to, uint32_t flags = 0) const;
private:
// `objects` and `objectsSize` always 0 for RPC Parcels.
@@ -1594,8 +1594,7 @@
// ---------------------------------------------------------------------------
-inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
-{
+inline std::ostream& operator<<(std::ostream& to, const Parcel& parcel) {
parcel.print(to);
return to;
}
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 7b662df..5e5d4ea 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -100,6 +100,8 @@
NONE = 0,
// Send file descriptors via unix domain socket ancillary data.
UNIX = 1,
+ // Send file descriptors as Trusty IPC handles.
+ TRUSTY = 2,
};
/**
diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
index bf9c92b..eb98042 100644
--- a/libs/binder/include/binder/TextOutput.h
+++ b/libs/binder/include/binder/TextOutput.h
@@ -94,7 +94,7 @@
uint32_t mCode;
};
-TextOutput& operator<<(TextOutput& to, const TypeCode& val);
+std::ostream& operator<<(std::ostream& to, const TypeCode& val);
class HexDump
{
@@ -123,7 +123,7 @@
bool mCArrayStyle;
};
-TextOutput& operator<<(TextOutput& to, const HexDump& val);
+std::ostream& operator<<(std::ostream& to, const HexDump& val);
inline TextOutput& operator<<(TextOutput& to,
decltype(std::endl<char,
std::char_traits<char>>)
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 7ea9be7..fccc0af 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -349,7 +349,7 @@
/**
* See AIBinder_Weak_promote.
*/
- SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
+ SpAIBinder promote() const { return SpAIBinder(AIBinder_Weak_promote(get())); }
};
namespace internal {
diff --git a/libs/binder/ndk/include_platform/android/binder_libbinder.h b/libs/binder/ndk/include_platform/android/binder_libbinder.h
index dfe12a1..74a7157 100644
--- a/libs/binder/ndk/include_platform/android/binder_libbinder.h
+++ b/libs/binder/ndk/include_platform/android/binder_libbinder.h
@@ -16,7 +16,7 @@
#pragma once
-#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
+#if (!defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)) || defined(__TRUSTY__)
#include <android/binder_ibinder.h>
#include <android/binder_parcel.h>
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 6d29238..01b9472 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -670,6 +670,26 @@
EXPECT_EQ(42, pparcel->readInt32());
}
+TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) {
+ for (const ndk::SpAIBinder& binder :
+ {// remote
+ ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)),
+ // local
+ ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) {
+ // get a const ScopedAIBinder_Weak and verify promote
+ EXPECT_NE(binder.get(), nullptr);
+ const ndk::ScopedAIBinder_Weak wkAIBinder =
+ ndk::ScopedAIBinder_Weak(AIBinder_Weak_new(binder.get()));
+ EXPECT_EQ(wkAIBinder.promote().get(), binder.get());
+ // get another ScopedAIBinder_Weak and verify
+ ndk::ScopedAIBinder_Weak wkAIBinder2 =
+ ndk::ScopedAIBinder_Weak(AIBinder_Weak_new(binder.get()));
+ EXPECT_FALSE(AIBinder_Weak_lt(wkAIBinder.get(), wkAIBinder2.get()));
+ EXPECT_FALSE(AIBinder_Weak_lt(wkAIBinder2.get(), wkAIBinder.get()));
+ EXPECT_EQ(wkAIBinder2.promote(), wkAIBinder.promote());
+ }
+}
+
class MyResultReceiver : public BnResultReceiver {
public:
Mutex mMutex;
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index b15a225..a3ed571 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -71,4 +71,13 @@
ParcelFileDescriptor echoAsFile(@utf8InCpp String content);
ParcelFileDescriptor concatFiles(in List<ParcelFileDescriptor> files);
+
+ // FDs sent via `blockingSendFdOneway` can be received via
+ // `blockingRecvFd`. The handler for `blockingSendFdOneway` will block
+ // until the next `blockingRecvFd` call.
+ //
+ // This is useful for carefully controlling how/when oneway transactions
+ // get queued.
+ oneway void blockingSendFdOneway(in ParcelFileDescriptor fd);
+ ParcelFileDescriptor blockingRecvFd();
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 6e1c8ac..25b524f 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -115,6 +115,7 @@
BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
+ BINDER_LIB_TEST_GET_NON_BLOCKING_FD,
BINDER_LIB_TEST_REJECT_OBJECTS,
BINDER_LIB_TEST_CAN_GET_SID,
BINDER_LIB_TEST_GET_MAX_THREAD_COUNT,
@@ -1158,6 +1159,21 @@
EXPECT_EQ(readValue, testValue);
}
+TEST_F(BinderLibTest, FileDescriptorRemainsNonBlocking) {
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ Parcel reply;
+ EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_NON_BLOCKING_FD, {} /*data*/, &reply),
+ StatusEq(NO_ERROR));
+ base::unique_fd fd;
+ EXPECT_THAT(reply.readUniqueFileDescriptor(&fd), StatusEq(OK));
+
+ const int result = fcntl(fd.get(), F_GETFL);
+ ASSERT_NE(result, -1);
+ EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
+}
+
// see ProcessState.cpp BINDER_VM_SIZE = 1MB.
// This value is not exposed, but some code in the framework relies on being able to use
// buffers near the cap size.
@@ -1801,6 +1817,28 @@
reply->writeUint64Vector(vector);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_GET_NON_BLOCKING_FD: {
+ std::array<int, 2> sockets;
+ const bool created = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets.data()) == 0;
+ if (!created) {
+ ALOGE("Could not create socket pair");
+ return UNKNOWN_ERROR;
+ }
+
+ const int result = fcntl(sockets[0], F_SETFL, O_NONBLOCK);
+ if (result != 0) {
+ ALOGE("Could not make socket non-blocking: %s", strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+ base::unique_fd out(sockets[0]);
+ status_t writeResult = reply->writeUniqueFileDescriptor(out);
+ if (writeResult != NO_ERROR) {
+ ALOGE("Could not write unique_fd");
+ return writeResult;
+ }
+ close(sockets[1]); // we don't need the other side of the fd
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_REJECT_OBJECTS: {
return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR;
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 8841021..7294305 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -85,6 +85,11 @@
return base::StringPrintf("unexpected state %d", wstatus);
}
+static void debugBacktrace(pid_t pid) {
+ std::cerr << "TAKING BACKTRACE FOR PID " << pid << std::endl;
+ system((std::string("debuggerd -b ") + std::to_string(pid)).c_str());
+}
+
class Process {
public:
Process(Process&&) = default;
@@ -125,6 +130,8 @@
// Kill the process. Avoid if possible. Shutdown gracefully via an RPC instead.
void terminate() { kill(mPid, SIGTERM); }
+ pid_t getPid() { return mPid; }
+
private:
std::function<void(int wstatus)> mCustomExitStatusCheck;
pid_t mPid = 0;
@@ -173,7 +180,21 @@
wp<RpcSession> weakSession = session;
session = nullptr;
- EXPECT_EQ(nullptr, weakSession.promote()) << "Leaked session";
+
+ // b/244325464 - 'getStrongCount' is printing '1' on failure here, which indicates the
+ // the object should not actually be promotable. By looping, we distinguish a race here
+ // from a bug causing the object to not be promotable.
+ for (size_t i = 0; i < 3; i++) {
+ sp<RpcSession> strongSession = weakSession.promote();
+ EXPECT_EQ(nullptr, strongSession)
+ << (debugBacktrace(host.getPid()), debugBacktrace(getpid()),
+ "Leaked sess: ")
+ << strongSession->getStrongCount() << " checked time " << i;
+
+ if (strongSession != nullptr) {
+ sleep(1);
+ }
+ }
}
}
};
@@ -817,12 +838,12 @@
ts.push_back(std::thread([&] { proc.rootIface->lockUnlock(); }));
}
- usleep(100000); // give chance for calls on other threads
+ usleep(10000); // give chance for calls on other threads
// other calls still work
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
- constexpr size_t blockTimeMs = 500;
+ constexpr size_t blockTimeMs = 50;
size_t epochMsBefore = epochMillis();
// after this, we should never see a response within this time
EXPECT_OK(proc.rootIface->unlockInMsAsync(blockTimeMs));
@@ -951,6 +972,45 @@
EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
}
+TEST_P(BinderRpc, OnewayCallQueueingWithFds) {
+ if (!supportsFdTransport()) {
+ GTEST_SKIP() << "Would fail trivially (which is tested elsewhere)";
+ }
+ if (clientOrServerSingleThreaded()) {
+ GTEST_SKIP() << "This test requires multiple threads";
+ }
+
+ // This test forces a oneway transaction to be queued by issuing two
+ // `blockingSendFdOneway` calls, then drains the queue by issuing two
+ // `blockingRecvFd` calls.
+ //
+ // For more details about the queuing semantics see
+ // https://developer.android.com/reference/android/os/IBinder#FLAG_ONEWAY
+
+ auto proc = createRpcTestSocketServerProcess({
+ .numThreads = 3,
+ .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX,
+ .serverSupportedFileDescriptorTransportModes =
+ {RpcSession::FileDescriptorTransportMode::UNIX},
+ });
+
+ EXPECT_OK(proc.rootIface->blockingSendFdOneway(
+ android::os::ParcelFileDescriptor(mockFileDescriptor("a"))));
+ EXPECT_OK(proc.rootIface->blockingSendFdOneway(
+ android::os::ParcelFileDescriptor(mockFileDescriptor("b"))));
+
+ android::os::ParcelFileDescriptor fdA;
+ EXPECT_OK(proc.rootIface->blockingRecvFd(&fdA));
+ std::string result;
+ CHECK(android::base::ReadFdToString(fdA.get(), &result));
+ EXPECT_EQ(result, "a");
+
+ android::os::ParcelFileDescriptor fdB;
+ EXPECT_OK(proc.rootIface->blockingRecvFd(&fdB));
+ CHECK(android::base::ReadFdToString(fdB.get(), &result));
+ EXPECT_EQ(result, "b");
+}
+
TEST_P(BinderRpc, OnewayCallQueueing) {
if (clientOrServerSingleThreaded()) {
GTEST_SKIP() << "This test requires multiple threads";
@@ -1114,7 +1174,7 @@
}
std::unique_lock<std::mutex> lock(dr->mMtx);
- ASSERT_TRUE(dr->mCv.wait_for(lock, 1000ms, [&]() { return dr->dead; }));
+ ASSERT_TRUE(dr->mCv.wait_for(lock, 100ms, [&]() { return dr->dead; }));
// need to wait for the session to shutdown so we don't "Leak session"
EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
@@ -1149,7 +1209,7 @@
std::unique_lock<std::mutex> lock(dr->mMtx);
if (!dr->dead) {
- EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+ EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 100ms));
}
EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
@@ -1732,7 +1792,7 @@
bool shutdown = false;
for (int i = 0; i < 10 && !shutdown; i++) {
- usleep(300 * 1000); // 300ms; total 3s
+ usleep(30 * 1000); // 30ms; total 300ms
if (server->shutdown()) shutdown = true;
}
ASSERT_TRUE(shutdown) << "server->shutdown() never returns true";
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
index 712f37e..823bbf6 100644
--- a/libs/binder/tests/binderRpcTestCommon.h
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -172,6 +172,42 @@
return readFd;
}
+// A threadsafe channel where writes block until the value is read.
+template <typename T>
+class HandoffChannel {
+public:
+ void write(T v) {
+ {
+ RpcMutexUniqueLock lock(mMutex);
+ // Wait for space to send.
+ mCvEmpty.wait(lock, [&]() { return !mValue.has_value(); });
+ mValue.emplace(std::move(v));
+ }
+ mCvFull.notify_all();
+ RpcMutexUniqueLock lock(mMutex);
+ // Wait for it to be taken.
+ mCvEmpty.wait(lock, [&]() { return !mValue.has_value(); });
+ }
+
+ T read() {
+ RpcMutexUniqueLock lock(mMutex);
+ if (!mValue.has_value()) {
+ mCvFull.wait(lock, [&]() { return mValue.has_value(); });
+ }
+ T v = std::move(mValue.value());
+ mValue.reset();
+ lock.unlock();
+ mCvEmpty.notify_all();
+ return std::move(v);
+ }
+
+private:
+ RpcMutex mMutex;
+ RpcConditionVariable mCvEmpty;
+ RpcConditionVariable mCvFull;
+ std::optional<T> mValue;
+};
+
using android::binder::Status;
class MyBinderRpcSession : public BnBinderRpcSession {
@@ -379,6 +415,18 @@
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();
+ }
};
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 0210237..3904e1d 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -84,6 +84,7 @@
},
},
srcs: [
+ "random_binder.cpp",
"random_fd.cpp",
"random_parcel.cpp",
"libbinder_driver.cpp",
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
new file mode 100644
index 0000000..8fc9263
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+// Get a random binder object for use in fuzzing.
+//
+// May return nullptr.
+sp<IBinder> getRandomBinder(FuzzedDataProvider* provider);
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_binder.cpp b/libs/binder/tests/parcel_fuzzer/random_binder.cpp
new file mode 100644
index 0000000..8a1fecb
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/random_binder.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 <fuzzbinder/random_binder.h>
+
+#include <fuzzbinder/random_parcel.h>
+
+#include <android-base/logging.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class RandomBinder : public BBinder {
+public:
+ RandomBinder(const String16& descriptor, std::vector<uint8_t>&& bytes)
+ : mDescriptor(descriptor),
+ mBytes(std::move(bytes)),
+ mProvider(mBytes.data(), mBytes.size()) {}
+ const String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override {
+ (void)code;
+ (void)data;
+ (void)reply;
+ (void)flags; // note - for maximum coverage even ignore if oneway
+
+ if (mProvider.ConsumeBool()) {
+ return mProvider.ConsumeIntegral<status_t>();
+ }
+
+ if (reply == nullptr) return OK;
+
+ // TODO: things we could do to increase state space
+ // - also pull FDs and binders from 'data'
+ // (optionally combine these into random parcel 'options')
+ // - also pull FDs and binders from random parcel 'options'
+ RandomParcelOptions options;
+
+ // random output
+ std::vector<uint8_t> subData = mProvider.ConsumeBytes<uint8_t>(
+ mProvider.ConsumeIntegralInRange<size_t>(0, mProvider.remaining_bytes()));
+ fillRandomParcel(reply, FuzzedDataProvider(subData.data(), subData.size()), &options);
+
+ return OK;
+ }
+
+private:
+ String16 mDescriptor;
+
+ // note may not all be used
+ std::vector<uint8_t> mBytes;
+ FuzzedDataProvider mProvider;
+};
+
+sp<IBinder> getRandomBinder(FuzzedDataProvider* provider) {
+ auto makeFunc = provider->PickValueInArray<const std::function<sp<IBinder>()>>({
+ [&]() {
+ // descriptor is the length of a class name, e.g.
+ // "some.package.Foo"
+ std::string str = provider->ConsumeRandomLengthString(100 /*max length*/);
+
+ // arbitrarily consume remaining data to create a binder that can return
+ // random results - coverage guided fuzzer should ensure all of the remaining
+ // data isn't always used
+ std::vector<uint8_t> bytes = provider->ConsumeBytes<uint8_t>(
+ provider->ConsumeIntegralInRange<size_t>(0, provider->remaining_bytes()));
+
+ return new RandomBinder(String16(str.c_str()), std::move(bytes));
+ },
+ []() {
+ // this is the easiest remote binder to get ahold of, and it
+ // should be able to handle anything thrown at it, and
+ // essentially every process can talk to it, so it's a good
+ // candidate for checking usage of an actual BpBinder
+ return IInterface::asBinder(defaultServiceManager());
+ },
+ [&]() -> sp<IBinder> { return nullptr; },
+ });
+ return makeFunc();
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 51cb768..edc695f 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -17,23 +17,14 @@
#include <fuzzbinder/random_parcel.h>
#include <android-base/logging.h>
-#include <binder/IServiceManager.h>
#include <binder/RpcSession.h>
#include <binder/RpcTransportRaw.h>
+#include <fuzzbinder/random_binder.h>
#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
namespace android {
-class NamedBinder : public BBinder {
-public:
- NamedBinder(const String16& descriptor) : mDescriptor(descriptor) {}
- const String16& getInterfaceDescriptor() const override { return mDescriptor; }
-
-private:
- String16 mDescriptor;
-};
-
static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
CHECK(OK == p->write(data.data(), data.size()));
@@ -45,6 +36,11 @@
if (provider.ConsumeBool()) {
auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
CHECK_EQ(OK, session->addNullDebuggingClient());
+ // Set the protocol version so that we don't crash if the session
+ // actually gets used. This isn't cheating because the version should
+ // always be set if the session init succeeded and we aren't testing the
+ // session init here (it is bypassed by addNullDebuggingClient).
+ session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION);
p->markForRpc(session);
if (options->writeHeader) {
@@ -89,32 +85,16 @@
},
// write binder
[&]() {
- auto makeFunc = provider.PickValueInArray<const std::function<sp<IBinder>()>>({
- [&]() {
- // descriptor is the length of a class name, e.g.
- // "some.package.Foo"
- std::string str =
- provider.ConsumeRandomLengthString(100 /*max length*/);
- return new NamedBinder(String16(str.c_str()));
- },
- []() {
- // this is the easiest remote binder to get ahold of, and it
- // should be able to handle anything thrown at it, and
- // essentially every process can talk to it, so it's a good
- // candidate for checking usage of an actual BpBinder
- return IInterface::asBinder(defaultServiceManager());
- },
- [&]() -> sp<IBinder> {
- if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
- return options->extraBinders.at(
- provider.ConsumeIntegralInRange<
- size_t>(0, options->extraBinders.size() - 1));
- } else {
- return nullptr;
- }
- },
- });
- sp<IBinder> binder = makeFunc();
+ sp<IBinder> binder;
+ if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
+ binder = options->extraBinders.at(
+ provider.ConsumeIntegralInRange<size_t>(0,
+ options->extraBinders
+ .size() -
+ 1));
+ } else {
+ binder = getRandomBinder(&provider);
+ }
CHECK(OK == p->writeStrongBinder(binder));
},
});
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 1f9389a..397ff41 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -16,6 +16,7 @@
#if defined(TRUSTY_USERSPACE)
#include <openssl/rand.h>
+#include <trusty_ipc.h>
#else
#include <lib/rand/rand.h>
#endif
@@ -23,6 +24,7 @@
#include <binder/RpcTransportTipcTrusty.h>
#include "../OS.h"
+#include "TrustyStatus.h"
using android::base::Result;
@@ -43,9 +45,14 @@
#endif // TRUSTY_USERSPACE
}
-status_t dupFileDescriptor(int /*oldFd*/, int* /*newFd*/) {
- // TODO: implement separately
- return INVALID_OPERATION;
+status_t dupFileDescriptor(int oldFd, int* newFd) {
+ int res = dup(oldFd);
+ if (res < 0) {
+ return statusFromTrusty(res);
+ }
+
+ *newFd = res;
+ return OK;
}
std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() {
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index 0b67b9f..58bfe71 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "RpcTransportTipcTrusty"
+#include <inttypes.h>
#include <trusty_ipc.h>
#include <binder/RpcSession.h>
@@ -47,7 +48,7 @@
status_t interruptableWriteFully(
FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
- const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
+ const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
override {
if (niovs < 0) {
return BAD_VALUE;
@@ -58,12 +59,32 @@
size += iovs[i].iov_len;
}
+ handle_t msgHandles[IPC_MAX_MSG_HANDLES];
ipc_msg_t msg{
.num_iov = static_cast<uint32_t>(niovs),
.iov = iovs,
- .num_handles = 0, // TODO: add ancillaryFds
+ .num_handles = 0,
.handles = nullptr,
};
+
+ if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
+ if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) {
+ // This shouldn't happen because we check the FD count in RpcState.
+ ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: "
+ "%zu (max is %u). Aborting session.",
+ ancillaryFds->size(), IPC_MAX_MSG_HANDLES);
+ return BAD_VALUE;
+ }
+
+ for (size_t i = 0; i < ancillaryFds->size(); i++) {
+ msgHandles[i] =
+ std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
+ }
+
+ msg.num_handles = ancillaryFds->size();
+ msg.handles = msgHandles;
+ }
+
ssize_t rc = send_msg(mSocket.fd.get(), &msg);
if (rc == ERR_NOT_ENOUGH_BUFFER) {
// Peer is blocked, wait until it unblocks.
@@ -97,8 +118,7 @@
status_t interruptableReadFully(
FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
- std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
- override {
+ std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
if (niovs < 0) {
return BAD_VALUE;
}
@@ -124,11 +144,16 @@
return status;
}
+ LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES,
+ "Received too many handles %" PRIu32, mMessageInfo.num_handles);
+ bool haveHandles = mMessageInfo.num_handles != 0;
+ handle_t msgHandles[IPC_MAX_MSG_HANDLES];
+
ipc_msg_t msg{
.num_iov = static_cast<uint32_t>(niovs),
.iov = iovs,
- .num_handles = 0, // TODO: support ancillaryFds
- .handles = nullptr,
+ .num_handles = mMessageInfo.num_handles,
+ .handles = haveHandles ? msgHandles : 0,
};
ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
if (rc < 0) {
@@ -141,6 +166,28 @@
"Message offset exceeds length %zu/%zu", mMessageOffset,
mMessageInfo.len);
+ if (haveHandles) {
+ if (ancillaryFds != nullptr) {
+ ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles);
+ for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
+ ancillaryFds->emplace_back(base::unique_fd(msgHandles[i]));
+ }
+
+ // Clear the saved number of handles so we don't accidentally
+ // read them multiple times
+ mMessageInfo.num_handles = 0;
+ haveHandles = false;
+ } else {
+ ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles);
+ // It should be safe to continue here. We could abort, but then
+ // peers could DoS us by sending messages with handles in them.
+ // Close the handles since we are ignoring them.
+ for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
+ ::close(msgHandles[i]);
+ }
+ }
+ }
+
// Release the message if all of it has been read
if (mMessageOffset == mMessageInfo.len) {
releaseMessage();
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index cc31c95..7d9dd8c 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -60,6 +60,10 @@
std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); }
+ void setSupportedFileDescriptorTransportModes(
+ const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
+ mRpcServer->setSupportedFileDescriptorTransportModes(modes);
+ }
void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); }
void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); }
void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) {
diff --git a/libs/binder/trusty/ndk/include/sys/cdefs.h b/libs/binder/trusty/ndk/include/sys/cdefs.h
new file mode 100644
index 0000000..6a48d2b
--- /dev/null
+++ b/libs/binder/trusty/ndk/include/sys/cdefs.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <lk/compiler.h>
+
+/* Alias the bionic macros to the ones from lk/compiler.h */
+#define __BEGIN_DECLS __BEGIN_CDECLS
+#define __END_DECLS __END_CDECLS
+
+#define __INTRODUCED_IN(x) /* nothing on Trusty */
diff --git a/libs/binder/trusty/ndk/rules.mk b/libs/binder/trusty/ndk/rules.mk
new file mode 100644
index 0000000..03fd006
--- /dev/null
+++ b/libs/binder/trusty/ndk/rules.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2021 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)
+
+MODULE := $(LOCAL_DIR)
+
+LIBBINDER_NDK_DIR := frameworks/native/libs/binder/ndk
+
+MODULE_SRCS := \
+ $(LIBBINDER_NDK_DIR)/ibinder.cpp \
+ $(LIBBINDER_NDK_DIR)/libbinder.cpp \
+ $(LIBBINDER_NDK_DIR)/parcel.cpp \
+ $(LIBBINDER_NDK_DIR)/status.cpp \
+
+MODULE_EXPORT_INCLUDES += \
+ $(LOCAL_DIR)/include \
+ $(LIBBINDER_NDK_DIR)/include_cpp \
+ $(LIBBINDER_NDK_DIR)/include_ndk \
+ $(LIBBINDER_NDK_DIR)/include_platform \
+
+MODULE_LIBRARY_DEPS += \
+ trusty/user/base/lib/libstdc++-trusty \
+ frameworks/native/libs/binder/trusty \
+
+include make/library.mk
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 1fe8800..6af2cc1 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -668,10 +668,11 @@
// VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following
// four values cannot be known without a surface. Default values will
// be supplied anyway, but cannot be relied upon.
- width = 1000;
- height = 1000;
- transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- max_buffer_count = 10;
+ width = 0xFFFFFFFF;
+ height = 0xFFFFFFFF;
+ transform_hint = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
+ capabilities->minImageCount = 0xFFFFFFFF;
+ capabilities->maxImageCount = 0xFFFFFFFF;
} else {
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
@@ -703,9 +704,9 @@
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ capabilities->minImageCount = std::min(max_buffer_count, 3);
+ capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
}
- capabilities->minImageCount = std::min(max_buffer_count, 3);
- capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
capabilities->currentExtent =
VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};