Merge "Fix the secure flag check for blackout layer issue"
diff --git a/.clang-format b/.clang-format
index 03af56d..6725a1f 100644
--- a/.clang-format
+++ b/.clang-format
@@ -11,3 +11,4 @@
IndentWidth: 4
PenaltyBreakBeforeFirstCallParameter: 100000
SpacesBeforeTrailingComments: 1
+IncludeBlocks: Preserve
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9cab9b4..16ebf6f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,10 +5,10 @@
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/idlcli/
+ cmds/servicemanager/
include/input/
libs/binder/fuzzer/
- libs/binder/ndk/
- libs/binder/tests/fuzzers/
+ libs/binder/
libs/binderthreadstate/
libs/graphicsenv/
libs/gui/
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 2519ffa..6f5f70d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -62,7 +62,7 @@
using std::string;
-#define MAX_SYS_FILES 11
+#define MAX_SYS_FILES 12
const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -175,6 +175,7 @@
{ OPT, "events/power/suspend_resume/enable" },
{ OPT, "events/cpuhp/cpuhp_enter/enable" },
{ OPT, "events/cpuhp/cpuhp_exit/enable" },
+ { OPT, "events/cpuhp/cpuhp_pause/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
{ REQ, "events/memory_bus/enable" },
@@ -319,9 +320,6 @@
static const char* k_funcgraphProcPath =
"options/funcgraph-proc";
-static const char* k_funcgraphFlatPath =
- "options/funcgraph-flat";
-
static const char* k_ftraceFilterPath =
"set_ftrace_filter";
@@ -699,7 +697,6 @@
ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
- ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
// Set the requested filter functions.
ok &= truncateFile(k_ftraceFilterPath);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 006e532..37fc9a9 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -57,6 +57,8 @@
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_enter/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit/enable
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_pause/enable
+ chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_pause/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index f48f1fb..aff32c3 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -99,6 +99,7 @@
"libhidlbase",
"liblog",
"libutils",
+ "libbinderdebug",
],
srcs: [
"DumpstateService.cpp",
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
index e15ac3f..c2c8a72 100644
--- a/cmds/dumpstate/DumpPool.cpp
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -64,8 +64,8 @@
if (shutdown_ || threads_.empty()) {
return;
}
- while (!tasks_.empty()) tasks_.pop();
futures_map_.clear();
+ while (!tasks_.empty()) tasks_.pop();
shutdown_ = true;
condition_variable_.notify_all();
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f553697..b8df99f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -793,6 +793,9 @@
if (module_metadata_version != 0) {
printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
}
+ printf("SDK extension versions [r=%s s=%s]\n",
+ android::base::GetProperty("build.version.extensions.r", "-").c_str(),
+ android::base::GetProperty("build.version.extensions.s", "-").c_str());
printf("Kernel: ");
DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
@@ -2174,14 +2177,13 @@
}
/*
- * mount debugfs for non-user builds which launch with S and unmount it
- * after invoking dumpstateBoard_* methods. This is to enable debug builds
- * to not have debugfs mounted during runtime. It will also ensure that
- * debugfs is only accessed by the dumpstate HAL.
+ * mount debugfs for non-user builds with ro.product.debugfs_restrictions.enabled
+ * set to true and unmount it after invoking dumpstateBoard_* methods.
+ * This is to enable debug builds to not have debugfs mounted during runtime.
+ * It will also ensure that debugfs is only accessed by the dumpstate HAL.
*/
- auto api_level = android::base::GetIntProperty("ro.product.first_api_level", 0);
- bool mount_debugfs = !PropertiesHelper::IsUserBuild() && api_level >= 31;
-
+ auto mount_debugfs =
+ android::base::GetBoolProperty("ro.product.debugfs_restrictions.enabled", false);
if (mount_debugfs) {
RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
AS_ROOT_20);
@@ -2289,7 +2291,10 @@
}
if (mount_debugfs) {
- RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20);
+ auto keep_debugfs_mounted =
+ android::base::GetProperty("persist.dbg.keep_debugfs_mounted", "");
+ if (keep_debugfs_mounted.empty())
+ RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20);
}
auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
@@ -3024,11 +3029,14 @@
}
void Dumpstate::MaybeSnapshotWinTrace() {
- RunCommand(
- // Empty name because it's not intended to be classified as a bugreport section.
- // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
- "", {"cmd", "window", "tracing", "save-for-bugreport"},
- CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol.
+ for (const auto& service : {"window", "input_method"}) {
+ RunCommand(
+ // Empty name because it's not intended to be classified as a bugreport section.
+ // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
+ "", {"cmd", service, "tracing", "save-for-bugreport"},
+ CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ }
}
void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index c62d302..0712c0a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -411,7 +411,6 @@
}
TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
- SectionExists("HIGH connectivity", /* bytes= */ 3000);
SectionExists("connectivity", /* bytes= */ 5000);
}
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index b2518ad..db508b5 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -1032,12 +1032,12 @@
ZipArchiveHandle handle_;
};
-// Generate a quick wifi report redirected to a file, open it and verify entry exist.
-TEST_F(ZippedBugReportStreamTest, StreamWifiReport) {
- std::string out_path = kTestDataPath + "out.zip";
+// Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist.
+TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) {
+ std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip";
android::base::unique_fd out_fd;
CreateFd(out_path, &out_fd);
- ds_.options_->wifi_only = true;
+ ds_.options_->limited_only = true;
ds_.options_->stream_to_socket = true;
RedirectOutputToFd(out_fd);
@@ -1051,7 +1051,7 @@
ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
entry.uncompressed_length);
EXPECT_THAT(bugreport_txt_name,
- testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)"));
+ testing::ContainsRegex("(bugreport-.+(-[[:digit:]]+){6}\\.txt)"));
VerifyEntry(handle_, bugreport_txt_name, &entry);
}
@@ -1762,6 +1762,27 @@
EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
}
+TEST_F(DumpPoolTest, Shutdown_withoutCrash) {
+ bool run_1 = false;
+ auto dump_func_1 = [&]() {
+ run_1 = true;
+ };
+ auto dump_func = []() {
+ sleep(1);
+ };
+
+ dump_pool_->start(/* thread_counts = */1);
+ dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
+ dump_pool_->enqueueTask(/* task_name = */"2", dump_func);
+ dump_pool_->enqueueTask(/* task_name = */"3", dump_func);
+ dump_pool_->enqueueTask(/* task_name = */"4", dump_func);
+ dump_pool_->waitForTask("1", "", out_fd_.get());
+ dump_pool_->shutdown();
+
+ EXPECT_TRUE(run_1);
+ EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+}
+
class TaskQueueTest : public DumpstateBaseTest {
public:
void SetUp() {
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 91aa018..6ab6b7f 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -32,6 +32,7 @@
"libutils",
"liblog",
"libbinder",
+ "libbinderdebug",
],
static_libs: [
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 2a9b681..4f6a89e 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -2,3 +2,6 @@
nandana@google.com
jsharkey@android.com
+
+# for ServiceManager mock
+per-file dumpsys_test.cpp=smoreland@google.com
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a017246..ba1c449 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -25,6 +25,7 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/TextOutput.h>
+#include <binderdebug/BinderDebug.h>
#include <serviceutils/PriorityDumper.h>
#include <utils/Log.h>
#include <utils/Vector.h>
@@ -60,13 +61,15 @@
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES "
+ " dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--thread] [--help | -l | "
+ "--skip SERVICES "
"| SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
" -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
" --pid: dump PID instead of usual dump\n"
+ " --thread: dump thread usage instead of usual dump\n"
" --proto: filter services that support dumping data in proto format. Dumps\n"
" will be in proto format.\n"
" --priority LEVEL: filter services based on specified priority\n"
@@ -125,7 +128,8 @@
Type type = Type::DUMP;
int timeoutArgMs = 10000;
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
- static struct option longOptions[] = {{"pid", no_argument, 0, 0},
+ static struct option longOptions[] = {{"thread", no_argument, 0, 0},
+ {"pid", no_argument, 0, 0},
{"priority", required_argument, 0, 0},
{"proto", no_argument, 0, 0},
{"skip", no_argument, 0, 0},
@@ -163,6 +167,8 @@
}
} else if (!strcmp(longOptions[optionIndex].name, "pid")) {
type = Type::PID;
+ } else if (!strcmp(longOptions[optionIndex].name, "thread")) {
+ type = Type::THREAD;
}
break;
@@ -329,6 +335,23 @@
return OK;
}
+static status_t dumpThreadsToFd(const sp<IBinder>& service, const unique_fd& fd) {
+ pid_t pid;
+ status_t status = service->getDebugPid(&pid);
+ if (status != OK) {
+ return status;
+ }
+ BinderPidInfo pidInfo;
+ status = getBinderPidInfo(BinderDebugContext::BINDER, pid, &pidInfo);
+ if (status != OK) {
+ return status;
+ }
+ WriteStringToFd("Threads in use: " + std::to_string(pidInfo.threadUsage) + "/" +
+ std::to_string(pidInfo.threadCount) + "\n",
+ fd.get());
+ return OK;
+}
+
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
@@ -359,6 +382,9 @@
case Type::PID:
err = dumpPidToFd(service, remote_end);
break;
+ case Type::THREAD:
+ err = dumpThreadsToFd(service, remote_end);
+ break;
default:
std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
return;
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 929c55c..349947c 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -52,13 +52,14 @@
static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
enum class Type {
- DUMP, // dump using `dump` function
- PID, // dump pid of server only
+ DUMP, // dump using `dump` function
+ PID, // dump pid of server only
+ THREAD, // dump thread usage of server only
};
/**
* Starts a thread to connect to a service and get its dump output. The thread redirects
- * the output to a pipe. Thread must be stopped by a subsequent callto {@code
+ * the output to a pipe. Thread must be stopped by a subsequent call to {@code
* stopDumpThread}.
* @param serviceName
* @param args list of arguments to pass to service dump method.
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 6854c75..58fec30 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -19,6 +19,7 @@
"libbase",
"libbinder",
"libutils",
+ "libbinderdebug",
],
static_libs: [
@@ -26,6 +27,4 @@
"libgmock",
"libserviceutils",
],
-
- clang: true,
}
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
index 1a8c67f..c2351d9 100644
--- a/cmds/dumpsys/tests/AndroidTest.xml
+++ b/cmds/dumpsys/tests/AndroidTest.xml
@@ -23,4 +23,4 @@
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="dumpsys_test" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 67a77f6..c9d2dbb 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -16,12 +16,15 @@
#include "../dumpsys.h"
+#include <regex>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <android-base/file.h>
+#include <binder/Binder.h>
+#include <binder/ProcessState.h>
#include <serviceutils/PriorityDumper.h>
#include <utils/String16.h>
#include <utils/String8.h>
@@ -56,6 +59,7 @@
MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
MOCK_METHOD1(isDeclared, bool(const String16&));
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
+ MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
@@ -222,6 +226,10 @@
EXPECT_THAT(stdout_, HasSubstr(expected));
}
+ void AssertOutputFormat(const std::string format) {
+ EXPECT_THAT(stdout_, testing::MatchesRegex(format));
+ }
+
void AssertDumped(const std::string& service, const std::string& dump) {
EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
@@ -574,6 +582,30 @@
AssertOutput(std::to_string(getpid()) + "\n");
}
+// Tests 'dumpsys --thread'
+TEST_F(DumpsysTest, ListAllServicesWithThread) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--thread"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+
+ const std::string format("(.|\n)*((Threads in use: [0-9]+/[0-9]+)?\n-(.|\n)*){2}");
+ AssertOutputFormat(format);
+}
+
+// Tests 'dumpsys --thread service_name'
+TEST_F(DumpsysTest, ListServiceWithThread) {
+ ExpectCheckService("Locksmith");
+
+ CallMain({"--thread", "Locksmith"});
+ // returns an empty string without root enabled
+ const std::string format("(^$|Threads in use: [0-9]/[0-9]+\n)");
+ AssertOutputFormat(format);
+}
+
TEST_F(DumpsysTest, GetBytesWritten) {
const char* serviceName = "service2";
const char* dumpContents = "dump1";
@@ -599,3 +631,13 @@
/* as_proto = */ false, elapsedDuration, bytesWritten);
EXPECT_THAT(status, Eq(INVALID_OPERATION));
}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ // start a binder thread pool for testing --thread option
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
+ ProcessState::self()->startThreadPool();
+
+ return RUN_ALL_TESTS();
+}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index cf23f8a..d09d3e8 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -189,8 +189,8 @@
"liblog",
"libutils",
],
- static_libs: [
- "libapexd",
+ required: [
+ "apexd"
],
}
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 379cf92..83f01de 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -20,21 +20,19 @@
#include <sys/stat.h>
#include <sys/wait.h>
+#include <array>
#include <fstream>
#include <sstream>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <libdm/dm.h>
#include <selinux/android.h>
-#include <apex_file_repository.h>
-#include <apex_constants.h>
-#include <apexd.h>
-
#include "installd_constants.h"
#include "otapreopt_utils.h"
@@ -64,47 +62,23 @@
}
}
-static std::vector<apex::ApexFile> ActivateApexPackages() {
- // The logic here is (partially) copied and adapted from
- // system/apex/apexd/apexd.cpp.
- //
- // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
- std::vector<std::string> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
- apex::kApexPackageVendorDir};
- // Initialize ApexFileRepository used internally in ScanPackagesDirAndActivate.
- // This is a quick fix to fix apex activation in otapreopt_chroot.
- apex::ApexFileRepository::GetInstance().AddPreInstalledApex(apex_dirs);
- for (const auto& dir : apex_dirs) {
- // Cast call to void to suppress warn_unused_result.
- static_cast<void>(apex::ScanPackagesDirAndActivate(dir.c_str()));
+static void ActivateApexPackages() {
+ std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"};
+ std::string apexd_error_msg;
+
+ bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+ if (!exec_result) {
+ PLOG(ERROR) << "Running otapreopt failed: " << apexd_error_msg;
+ exit(220);
}
- return apex::GetActivePackages();
}
-static void CreateApexInfoList(const std::vector<apex::ApexFile>& apex_files) {
- // Setup the apex-info-list.xml file
- const std::string apex_info_file = std::string(apex::kApexRoot) + "/" + apex::kApexInfoList;
- std::fstream xml(apex_info_file.c_str(), std::ios::out | std::ios::trunc);
- if (!xml.is_open()) {
- PLOG(ERROR) << "Failed to open " << apex_info_file;
- exit(216);
- }
-
- // we do not care about inactive apexs
- std::vector<apex::ApexFile> inactive;
- apex::CollectApexInfoList(xml, apex_files, inactive);
- xml.flush();
- xml.close();
-}
-
-static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
- for (const apex::ApexFile& apex_file : active_packages) {
- const std::string& package_path = apex_file.GetPath();
- base::Result<void> status = apex::DeactivatePackage(package_path);
- if (!status.ok()) {
- LOG(ERROR) << "Failed to deactivate " << package_path << ": "
- << status.error();
- }
+static void DeactivateApexPackages() {
+ std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"};
+ std::string apexd_error_msg;
+ bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+ if (!exec_result) {
+ PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg;
}
}
@@ -205,6 +179,11 @@
// want it for product APKs. Same notes as vendor above.
TryExtraMount("product", arg[2], "/postinstall/product");
+ // Try to mount the system_ext partition. update_engine doesn't do this for
+ // us, but we want it for system_ext APKs. Same notes as vendor and product
+ // above.
+ TryExtraMount("system_ext", arg[2], "/postinstall/system_ext");
+
constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
// Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
if (mount("tmpfs", kPostInstallLinkerconfig, "tmpfs", 0, nullptr) != 0) {
@@ -267,27 +246,57 @@
exit(205);
}
+ // Call apexd --unmount-all to free up loop and dm block devices, so that we can re-use
+ // them during the next invocation. Since otapreopt_chroot calls exit in case something goes
+ // wrong we need to register our own atexit handler.
+ // We want to register this handler before actually activating apex packages. This is mostly
+ // due to the fact that if fail to unmount apexes, then on the next run of otapreopt_chroot
+ // we will ask for new loop devices instead of re-using existing ones, and we really don't want
+ // to do that. :)
+ if (atexit(DeactivateApexPackages) != 0) {
+ LOG(ERROR) << "Failed to register atexit hander";
+ exit(206);
+ }
+
// Try to mount APEX packages in "/apex" in the chroot dir. We need at least
// the ART APEX, as it is required by otapreopt to run dex2oat.
- std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
- CreateApexInfoList(active_packages);
+ ActivateApexPackages();
+ auto cleanup = android::base::make_scope_guard([](){
+ std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"};
+ std::string apexd_error_msg;
+ bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+ if (!exec_result) {
+ PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg;
+ }
+ });
// Check that an ART APEX has been activated; clean up and exit
// early otherwise.
static constexpr const std::string_view kRequiredApexs[] = {
"com.android.art",
"com.android.runtime",
};
- for (std::string_view apex : kRequiredApexs) {
- if (std::none_of(active_packages.begin(), active_packages.end(),
- [&](const apex::ApexFile& package) {
- return package.GetManifest().name() == apex;
- })) {
- LOG(FATAL_WITHOUT_ABORT) << "No activated " << apex << " APEX package.";
- DeactivateApexPackages(active_packages);
- exit(217);
+ std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
+ DIR* apex_dir = opendir("/apex");
+ if (apex_dir == nullptr) {
+ PLOG(ERROR) << "unable to open /apex";
+ exit(220);
+ }
+ for (dirent* entry = readdir(apex_dir); entry != nullptr; entry = readdir(apex_dir)) {
+ for (int i = 0; i < found_apexs.size(); i++) {
+ if (kRequiredApexs[i] == std::string_view(entry->d_name)) {
+ found_apexs[i] = true;
+ break;
+ }
}
}
+ closedir(apex_dir);
+ auto it = std::find(found_apexs.cbegin(), found_apexs.cend(), false);
+ if (it != found_apexs.cend()) {
+ LOG(ERROR) << "No activated " << kRequiredApexs[std::distance(found_apexs.cbegin(), it)]
+ << " package!";
+ exit(221);
+ }
// Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category
if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
@@ -323,9 +332,6 @@
LOG(ERROR) << "Running otapreopt failed: " << error_msg;
}
- // Tear down the work down by the apexd logic. (i.e. deactivate packages).
- DeactivateApexPackages(active_packages);
-
if (!exec_result) {
exit(213);
}
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index 17ea903..a27fd10 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -86,7 +86,7 @@
bool generate_compact_dex,
bool use_jitzygote_image,
const char* compilation_reason) {
- PrepareBootImageAndBootClasspathFlags(use_jitzygote_image);
+ PrepareBootImageFlags(use_jitzygote_image);
PrepareInputFileFlags(output_oat, output_vdex, output_image, input_dex, input_vdex,
dex_metadata, profile, swap_fd, class_loader_context,
@@ -112,7 +112,7 @@
RunDex2Oat::~RunDex2Oat() {}
-void RunDex2Oat::PrepareBootImageAndBootClasspathFlags(bool use_jitzygote_image) {
+void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote_image) {
std::string boot_image;
if (use_jitzygote_image) {
boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
@@ -120,23 +120,6 @@
boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
}
AddArg(boot_image);
-
- // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
- // BOOTCLASSPATH.
- char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
- if (dex2oat_bootclasspath != nullptr) {
- AddRuntimeArg(StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath));
- }
-
- std::string updatable_bcp_packages =
- MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
- "--updatable-bcp-packages-file=%s");
- if (updatable_bcp_packages.empty()) {
- // Make dex2oat fail by providing non-existent file name.
- updatable_bcp_packages =
- "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
- }
- AddArg(updatable_bcp_packages);
}
void RunDex2Oat::PrepareInputFileFlags(const UniqueFile& output_oat,
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index 325a3a2..475e124 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -56,7 +56,7 @@
void Exec(int exit_code);
protected:
- void PrepareBootImageAndBootClasspathFlags(bool use_jitzygote_image);
+ void PrepareBootImageFlags(bool use_jitzygote_image);
void PrepareInputFileFlags(const UniqueFile& output_oat,
const UniqueFile& output_vdex,
const UniqueFile& output_image,
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
index 3813cf7..0a638cd 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -175,8 +175,6 @@
default_expected_flags_["--swap-fd"] = FLAG_UNUSED;
default_expected_flags_["--class-loader-context"] = FLAG_UNUSED;
default_expected_flags_["--class-loader-context-fds"] = FLAG_UNUSED;
- default_expected_flags_["--updatable-bcp-packages-file"] =
- "=/nonx/updatable-bcp-packages.txt";
// Arch
default_expected_flags_["--instruction-set"] = "=arm64";
@@ -320,28 +318,6 @@
VerifyExpectedFlags();
}
-TEST_F(RunDex2OatTest, DEX2OATBOOTCLASSPATH) {
- ASSERT_EQ(nullptr, getenv("DEX2OATBOOTCLASSPATH"));
- ASSERT_EQ(0, setenv("DEX2OATBOOTCLASSPATH", "foobar", /*override=*/ false))
- << "Failed to setenv: " << strerror(errno);
-
- CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
-
- SetExpectedFlagUsed("-Xbootclasspath", ":foobar");
- VerifyExpectedFlags();
-
- ASSERT_EQ(0, unsetenv("DEX2OATBOOTCLASSPATH"))
- << "Failed to setenv: " << strerror(errno);
-}
-
-TEST_F(RunDex2OatTest, UpdatableBootClassPath) {
- setSystemProperty("dalvik.vm.dex2oat-updatable-bcp-packages-file", "/path/to/file");
- CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
-
- SetExpectedFlagUsed("--updatable-bcp-packages-file", "=/path/to/file");
- VerifyExpectedFlags();
-}
-
TEST_F(RunDex2OatTest, DoNotGenerateCompactDex) {
auto args = RunDex2OatArgs::MakeDefaultTestArgs();
args->generate_compact_dex = false;
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index fbf1e0c..e272025 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -351,7 +351,7 @@
uid = kTestAppUid;
}
if (class_loader_context == nullptr) {
- class_loader_context = "&";
+ class_loader_context = "PCL[]";
}
int32_t dexopt_needed = 0; // does not matter;
std::optional<std::string> out_path; // does not matter
@@ -478,7 +478,7 @@
bool should_binder_call_succeed,
/*out */ binder::Status* binder_result) {
std::optional<std::string> out_path = oat_dir ? std::make_optional<std::string>(oat_dir) : std::nullopt;
- std::string class_loader_context = "&";
+ std::string class_loader_context = "PCL[]";
int32_t target_sdk_version = 0; // default
std::string profile_name = "primary.prof";
std::optional<std::string> dm_path_opt = dm_path ? std::make_optional<std::string>(dm_path) : std::nullopt;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c47df52..c4ecd07 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1062,6 +1062,8 @@
static const char* kProcFilesystems = "/proc/filesystems";
bool supports_sdcardfs() {
+ if (!property_get_bool("external_storage.sdcardfs.enabled", true))
+ return false;
std::string supported;
if (!android::base::ReadFileToString(kProcFilesystems, &supported)) {
PLOG(ERROR) << "Failed to read supported filesystems";
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index d5110f6..2722e21 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -417,7 +417,7 @@
}
}
out << "-->" << std::endl;
- out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlags::HALS_ONLY);
+ out << vintf::toXml(manifest, vintf::SerializeFlags::HALS_ONLY);
}
std::string ListCommand::INIT_VINTF_NOTES{
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index b6ff28d..6f08f74 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -47,8 +47,6 @@
using ::android::hardware::Void;
using android::vintf::Arch;
using android::vintf::CompatibilityMatrix;
-using android::vintf::gCompatibilityMatrixConverter;
-using android::vintf::gHalManifestConverter;
using android::vintf::HalManifest;
using android::vintf::Transport;
using android::vintf::VintfObject;
@@ -508,10 +506,10 @@
EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
EXPECT_EQ("", err.str());
+ std::string error;
vintf::HalManifest m;
- EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
- << "--init-vintf does not emit valid HAL manifest: "
- << vintf::gHalManifestConverter.lastError();
+ EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error))
+ << "--init-vintf does not emit valid HAL manifest: " << error;
}
// test default columns
@@ -775,10 +773,10 @@
auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
- ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
- ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
- ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
- ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
+ ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml));
+ ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml));
+ ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml));
+ ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml));
ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
@@ -964,7 +962,7 @@
" </hal>\n"
"</manifest>";
auto manifest = std::make_shared<HalManifest>();
- EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
+ EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml));
EXPECT_CALL(*mockList, getDeviceManifest())
.Times(AnyNumber())
.WillRepeatedly(Return(manifest));
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 9de344a..3ebdeee 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -14,6 +14,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
srcs: [
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 0dbab4e..b429fb3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -58,22 +58,34 @@
return false;
}
-static bool isVintfDeclared(const std::string& name) {
- 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;
- return false;
- }
- const std::string package = name.substr(0, lastDot);
- const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
- const std::string instance = name.substr(firstSlash+1);
+struct AidlName {
+ std::string package;
+ std::string iface;
+ std::string instance;
- bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
- if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+ static bool fill(const std::string& name, AidlName* aname) {
+ 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;
+ return false;
+ }
+ aname->package = name.substr(0, lastDot);
+ aname->iface = name.substr(lastDot + 1, firstSlash - lastDot - 1);
+ aname->instance = name.substr(firstSlash + 1);
+ return true;
+ }
+};
+
+static bool isVintfDeclared(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return false;
+
+ 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.";
- return true;
+ return true; // break
}
return false; // continue
});
@@ -81,13 +93,34 @@
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
- << " in the VINTF manifest.";
+ LOG(ERROR) << "Could not find " << aname.package << "." << aname.iface << "/"
+ << aname.instance << " in the VINTF manifest.";
}
return found;
}
+static std::optional<std::string> getVintfUpdatableApex(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return std::nullopt;
+
+ std::optional<std::string> updatableViaApex;
+
+ forEachManifest([&](const ManifestWithDescription& mwd) {
+ mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+ if (manifestInstance.format() != vintf::HalFormat::AIDL) return true;
+ if (manifestInstance.package() != aname.package) return true;
+ if (manifestInstance.interface() != aname.iface) return true;
+ if (manifestInstance.instance() != aname.instance) return true;
+ updatableViaApex = manifestInstance.updatableViaApex();
+ return false; // break (libvintf uses opposite convention)
+ });
+ return false; // continue
+ });
+
+ return updatableViaApex;
+}
+
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
@@ -239,7 +272,8 @@
#endif // !VENDORSERVICEMANAGER
// implicitly unlinked when the binder is removed
- if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) {
+ if (binder->remoteBinder() != nullptr &&
+ binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -307,7 +341,9 @@
return Status::fromExceptionCode(Status::EX_NULL_POINTER);
}
- if (OK != IInterface::asBinder(callback)->linkToDeath(this)) {
+ if (OK !=
+ IInterface::asBinder(callback)->linkToDeath(
+ sp<ServiceManager>::fromExisting(this))) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -385,6 +421,22 @@
return Status::ok();
}
+Status ServiceManager::updatableViaApex(const std::string& name,
+ std::optional<std::string>* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ *outReturn = std::nullopt;
+
+#ifndef VENDORSERVICEMANAGER
+ *outReturn = getVintfUpdatableApex(name);
+#endif
+ return Status::ok();
+}
+
void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found) {
@@ -461,7 +513,8 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
- if (OK != IInterface::asBinder(cb)->linkToDeath(this)) {
+ if (OK !=
+ IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) {
LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -491,7 +544,7 @@
}
ssize_t ServiceManager::Service::getNodeStrongRefCount() {
- sp<BpBinder> bpBinder = binder->remoteBinder();
+ sp<BpBinder> bpBinder = sp<BpBinder>::fromExisting(binder->remoteBinder());
if (bpBinder == nullptr) return -1;
return ProcessState::self()->getStrongRefCountForNode(bpBinder);
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c089115..4f23c21 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -46,6 +46,8 @@
binder::Status isDeclared(const std::string& name, bool* outReturn) override;
binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
+ binder::Status updatableViaApex(const std::string& name,
+ std::optional<std::string>* outReturn) override;
binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
const sp<IClientCallback>& cb) override;
binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 627dfe6..8c1beac 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -39,7 +39,7 @@
class BinderCallback : public LooperCallback {
public:
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
- sp<BinderCallback> cb = new BinderCallback;
+ sp<BinderCallback> cb = sp<BinderCallback>::make();
int binder_fd = -1;
IPCThreadState::self()->setupPolling(&binder_fd);
@@ -65,7 +65,7 @@
class ClientCallbackCallback : public LooperCallback {
public:
static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
- sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager);
+ sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager);
int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);
@@ -105,6 +105,7 @@
return 1; // Continue receiving callbacks.
}
private:
+ friend sp<ClientCallbackCallback>;
ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}
sp<ServiceManager> mManager;
};
@@ -120,7 +121,7 @@
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
- sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());
+ sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
}
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index fb9f9df..5d5a75e 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -46,7 +46,7 @@
}
};
- return new LinkableBinder;
+ return sp<LinkableBinder>::make();
}
class MockAccess : public Access {
@@ -71,7 +71,7 @@
ON_CALL(*access, canFind(_, _)).WillByDefault(Return(true));
ON_CALL(*access, canList(_)).WillByDefault(Return(true));
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
return sm;
}
@@ -119,7 +119,7 @@
.uid = uid,
}));
EXPECT_CALL(*access, canAdd(_, _)).Times(0);
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
@@ -161,7 +161,7 @@
EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(false));
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
@@ -194,7 +194,7 @@
EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true));
EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(false));
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
@@ -218,7 +218,7 @@
EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true));
EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true));
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
sp<IBinder> service = getBinder();
EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/,
@@ -244,7 +244,7 @@
// TODO(b/136023468): when security check is first, this should be called first
// EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true));
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
@@ -261,7 +261,7 @@
EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
EXPECT_CALL(*access, canList(_)).WillOnce(Return(false));
- sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access));
+ sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access));
std::vector<std::string> out;
EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk());
@@ -329,9 +329,9 @@
EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false));
- sp<ServiceManager> sm = new ServiceManager(std::move(access));
+ sp<ServiceManager> sm = sp<ServiceManager>::make(std::move(access));
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(),
Status::EX_SECURITY);
@@ -343,9 +343,9 @@
EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{}));
EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false));
- sp<ServiceManager> sm = new ServiceManager(std::move(access));
+ sp<ServiceManager> sm = sp<ServiceManager>::make(std::move(access));
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
// should always hit security error first
EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(),
@@ -355,7 +355,7 @@
TEST(ServiceNotifications, InvalidName) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(),
Status::EX_ILLEGAL_ARGUMENT);
@@ -371,7 +371,7 @@
TEST(ServiceNotifications, Unregister) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk());
EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0);
@@ -380,7 +380,7 @@
TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(),
Status::EX_ILLEGAL_STATE);
@@ -389,7 +389,7 @@
TEST(ServiceNotifications, NoNotification) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk());
EXPECT_TRUE(sm->addService("otherservice", getBinder(),
@@ -402,7 +402,7 @@
TEST(ServiceNotifications, GetNotification) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
sp<IBinder> service = getBinder();
@@ -417,7 +417,7 @@
TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
sp<IBinder> service = getBinder();
@@ -433,7 +433,7 @@
TEST(ServiceNotifications, GetMultipleNotification) {
auto sm = getPermissiveServiceManager();
- sp<CallbackHistorian> cb = new CallbackHistorian;
+ sp<CallbackHistorian> cb = sp<CallbackHistorian>::make();
sp<IBinder> binder1 = getBinder();
sp<IBinder> binder2 = getBinder();
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 098d915..3f110c9 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -58,21 +58,11 @@
// transport itself and should be moved to AIDL or in domain-specific libs.
//
// Currently, these are only on system android (not vendor, not host)
+// TODO(b/183654927) - move these into separate libraries
libbinder_device_interface_sources = [
- "ActivityManager.cpp",
- "AppOpsManager.cpp",
- "IActivityManager.cpp",
- "IAppOpsCallback.cpp",
- "IAppOpsService.cpp",
- "IBatteryStats.cpp",
- "IMediaResourceMonitor.cpp",
"IPermissionController.cpp",
- "IProcessInfoService.cpp",
- "IUidObserver.cpp",
"PermissionCache.cpp",
"PermissionController.cpp",
- "ProcessInfoService.cpp",
- "IpPrefix.cpp",
]
cc_library {
@@ -124,11 +114,16 @@
"ParcelFileDescriptor.cpp",
"PersistableBundle.cpp",
"ProcessState.cpp",
+ "RpcAddress.cpp",
+ "RpcConnection.cpp",
+ "RpcServer.cpp",
+ "RpcState.cpp",
"Static.cpp",
"Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"Utils.cpp",
+ ":packagemanager_aidl",
":libbinder_aidl",
],
@@ -164,6 +159,7 @@
"-Werror",
"-Wzero-as-null-pointer-constant",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
product_variables: {
binder32bit: {
@@ -196,6 +192,9 @@
// Only check our headers
"--header-filter=^.*frameworks/native/libs/binder/.*.h$",
],
+ tidy_checks: [
+ "-performance-no-int-to-ptr",
+ ],
tidy_checks_as_errors: [
// Explicitly list the checks that should not occur in this module.
"abseil-*",
@@ -203,20 +202,9 @@
"bugprone-*",
"cert-*",
"clang-analyzer-*",
- "-clang-analyzer-core.CallAndMessage",
- "-clang-analyzer-core.uninitialized.Assign",
- "-clang-analyzer-unix.Malloc",
- "-clang-analyzer-deadcode.DeadStores",
- "-clang-analyzer-optin.cplusplus.UninitializedObject",
"google-*",
- "-google-readability-*",
- "-google-runtime-references",
"misc-*",
- "-misc-no-recursion",
- "-misc-redundant-expression",
- "-misc-unused-using-decls",
"performance*",
- "-performance-no-int-to-ptr",
"portability*",
],
@@ -230,9 +218,6 @@
filegroup {
name: "libbinder_aidl",
srcs: [
- "aidl/android/content/pm/IPackageChangeObserver.aidl",
- "aidl/android/content/pm/IPackageManagerNative.aidl",
- "aidl/android/content/pm/PackageChangeEvent.aidl",
"aidl/android/os/IClientCallback.aidl",
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
@@ -241,6 +226,16 @@
path: "aidl",
}
+filegroup {
+ name: "packagemanager_aidl",
+ srcs: [
+ "aidl/android/content/pm/IPackageChangeObserver.aidl",
+ "aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/content/pm/PackageChangeEvent.aidl",
+ ],
+ path: "aidl",
+}
+
aidl_interface {
name: "libbinder_aidl_test_stub",
unstable: true,
@@ -253,3 +248,56 @@
},
},
}
+
+// libbinder historically contained additional interfaces that provided specific
+// functionality in the platform but have nothing to do with binder itself. These
+// are moved out of libbinder in order to avoid the overhead of their vtables.
+// If you are working on or own one of these interfaces, the responsible things
+// to would be:
+// - give them a new home
+// - convert them to AIDL instead of having manually written parceling code
+
+cc_library {
+ name: "libbatterystats_aidl",
+ srcs: [
+ "IBatteryStats.cpp",
+ ],
+ export_include_dirs: ["include_batterystats"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+cc_library {
+ name: "libprocessinfoservice_aidl",
+ srcs: [
+ "IProcessInfoService.cpp",
+ "ProcessInfoService.cpp",
+ ],
+ export_include_dirs: ["include_processinfo"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "liblog",
+ ],
+}
+
+cc_library {
+ name: "libactivitymanager_aidl",
+ srcs: [
+ "ActivityManager.cpp",
+ "IActivityManager.cpp",
+ "IUidObserver.cpp",
+ ":activity_manager_procstate_aidl",
+ ],
+ export_include_dirs: ["include_activitymanager"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "liblog",
+ ],
+ aidl: {
+ export_aidl_headers: true,
+ },
+}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index ddda024..fdcf94a 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/RpcConnection.h>
#include <binder/Stability.h>
#include <cutils/compiler.h>
#include <utils/Log.h>
@@ -106,8 +107,7 @@
// ---------------------------------------------------------------------------
-
-BpBinder* BpBinder::create(int32_t handle) {
+sp<BpBinder> BpBinder::create(int32_t handle) {
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
trackedUid = IPCThreadState::self()->getCallingUid();
@@ -133,25 +133,56 @@
}
sTrackingMap[trackedUid]++;
}
- return new BpBinder(handle, trackedUid);
+ return sp<BpBinder>::make(BinderHandle{handle}, trackedUid);
}
-BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
- : mStability(0)
- , mHandle(handle)
- , mAlive(1)
- , mObitsSent(0)
- , mObituaries(nullptr)
- , mTrackedUid(trackedUid)
-{
- ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
+sp<BpBinder> BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) {
+ LOG_ALWAYS_FATAL_IF(connection == nullptr, "BpBinder::create null connection");
+ // These are not currently tracked, since there is no UID or other
+ // identifier to track them with. However, if similar functionality is
+ // needed, connection objects keep track of all BpBinder objects on a
+ // per-connection basis.
+
+ return sp<BpBinder>::make(SocketHandle{connection, address});
+}
+
+BpBinder::BpBinder(Handle&& handle)
+ : mStability(0),
+ mHandle(handle),
+ mAlive(true),
+ mObitsSent(false),
+ mObituaries(nullptr),
+ mTrackedUid(-1) {
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- IPCThreadState::self()->incWeakHandle(handle, this);
}
-int32_t BpBinder::handle() const {
- return mHandle;
+BpBinder::BpBinder(BinderHandle&& handle, int32_t trackedUid) : BpBinder(Handle(handle)) {
+ mTrackedUid = trackedUid;
+
+ ALOGV("Creating BpBinder %p handle %d\n", this, this->binderHandle());
+
+ IPCThreadState::self()->incWeakHandle(this->binderHandle(), this);
+}
+
+BpBinder::BpBinder(SocketHandle&& handle) : BpBinder(Handle(handle)) {
+ LOG_ALWAYS_FATAL_IF(rpcConnection() == nullptr, "BpBinder created w/o connection object");
+}
+
+bool BpBinder::isRpcBinder() const {
+ return std::holds_alternative<SocketHandle>(mHandle);
+}
+
+const RpcAddress& BpBinder::rpcAddress() const {
+ return std::get<SocketHandle>(mHandle).address;
+}
+
+const sp<RpcConnection>& BpBinder::rpcConnection() const {
+ return std::get<SocketHandle>(mHandle).connection;
+}
+
+int32_t BpBinder::binderHandle() const {
+ return std::get<BinderHandle>(mHandle).handle;
}
bool BpBinder::isDescriptorCached() const {
@@ -162,10 +193,13 @@
const String16& BpBinder::getInterfaceDescriptor() const
{
if (isDescriptorCached() == false) {
- Parcel send, reply;
+ sp<BpBinder> thiz = sp<BpBinder>::fromExisting(const_cast<BpBinder*>(this));
+
+ Parcel data;
+ data.markForBinder(thiz);
+ Parcel reply;
// do the IPC without a lock held.
- status_t err = const_cast<BpBinder*>(this)->transact(
- INTERFACE_TRANSACTION, send, &reply);
+ status_t err = thiz->transact(INTERFACE_TRANSACTION, data, &reply);
if (err == NO_ERROR) {
String16 res(reply.readString16());
Mutex::Autolock _l(mLock);
@@ -190,9 +224,10 @@
status_t BpBinder::pingBinder()
{
- Parcel send;
+ Parcel data;
+ data.markForBinder(sp<BpBinder>::fromExisting(this));
Parcel reply;
- return transact(PING_TRANSACTION, send, &reply);
+ return transact(PING_TRANSACTION, data, &reply);
}
status_t BpBinder::dump(int fd, const Vector<String16>& args)
@@ -236,8 +271,13 @@
}
}
- status_t status = IPCThreadState::self()->transact(
- mHandle, code, data, reply, flags);
+ status_t status;
+ if (CC_UNLIKELY(isRpcBinder())) {
+ status = rpcConnection()->transact(rpcAddress(), code, data, reply, flags);
+ } else {
+ status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
+ }
+
if (status == DEAD_OBJECT) mAlive = 0;
return status;
@@ -250,6 +290,8 @@
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
+ if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+
Obituary ob;
ob.recipient = recipient;
ob.cookie = cookie;
@@ -267,10 +309,10 @@
if (!mObituaries) {
return NO_MEMORY;
}
- ALOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+ ALOGV("Requesting death notification: %p handle %d\n", this, binderHandle());
getWeakRefs()->incWeak(this);
IPCThreadState* self = IPCThreadState::self();
- self->requestDeathNotification(mHandle, this);
+ self->requestDeathNotification(binderHandle(), this);
self->flushCommands();
}
ssize_t res = mObituaries->add(ob);
@@ -286,6 +328,8 @@
const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
wp<DeathRecipient>* outRecipient)
{
+ if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+
AutoMutex _l(mLock);
if (mObitsSent) {
@@ -303,9 +347,9 @@
}
mObituaries->removeAt(i);
if (mObituaries->size() == 0) {
- ALOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+ ALOGV("Clearing death notification: %p handle %d\n", this, binderHandle());
IPCThreadState* self = IPCThreadState::self();
- self->clearDeathNotification(mHandle, this);
+ self->clearDeathNotification(binderHandle(), this);
self->flushCommands();
delete mObituaries;
mObituaries = nullptr;
@@ -319,8 +363,10 @@
void BpBinder::sendObituary()
{
- ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
- this, mHandle, mObitsSent ? "true" : "false");
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(), "Cannot send obituary for remote binder.");
+
+ ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", this, binderHandle(),
+ mObitsSent ? "true" : "false");
mAlive = 0;
if (mObitsSent) return;
@@ -328,9 +374,9 @@
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits != nullptr) {
- ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+ ALOGV("Clearing sent death notification: %p handle %d\n", this, binderHandle());
IPCThreadState* self = IPCThreadState::self();
- self->clearDeathNotification(mHandle, this);
+ self->clearDeathNotification(binderHandle(), this);
self->flushCommands();
mObituaries = nullptr;
}
@@ -356,7 +402,7 @@
ALOGV("Reporting death to recipient: %p\n", recipient.get());
if (recipient == nullptr) return;
- recipient->binderDied(this);
+ recipient->binderDied(wp<BpBinder>::fromExisting(this));
}
@@ -388,7 +434,9 @@
BpBinder::~BpBinder()
{
- ALOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
+ ALOGV("Destroying BpBinder %p handle %d\n", this, binderHandle());
+
+ if (CC_UNLIKELY(isRpcBinder())) return;
IPCThreadState* ipc = IPCThreadState::self();
@@ -396,7 +444,8 @@
AutoMutex _l(sTrackingLock);
uint32_t trackedValue = sTrackingMap[mTrackedUid];
if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) {
- ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle);
+ ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this,
+ binderHandle());
} else {
if (CC_UNLIKELY(
(trackedValue & LIMIT_REACHED_MASK) &&
@@ -413,26 +462,31 @@
}
if (ipc) {
- ipc->expungeHandle(mHandle, this);
- ipc->decWeakHandle(mHandle);
+ ipc->expungeHandle(binderHandle(), this);
+ ipc->decWeakHandle(binderHandle());
}
}
void BpBinder::onFirstRef()
{
- ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
+ ALOGV("onFirstRef BpBinder %p handle %d\n", this, binderHandle());
+ if (CC_UNLIKELY(isRpcBinder())) return;
IPCThreadState* ipc = IPCThreadState::self();
- if (ipc) ipc->incStrongHandle(mHandle, this);
+ if (ipc) ipc->incStrongHandle(binderHandle(), this);
}
void BpBinder::onLastStrongRef(const void* /*id*/)
{
- ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
+ ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
+ if (CC_UNLIKELY(isRpcBinder())) {
+ (void)rpcConnection()->sendDecStrong(rpcAddress());
+ return;
+ }
IF_ALOGV() {
printRefs();
}
IPCThreadState* ipc = IPCThreadState::self();
- if (ipc) ipc->decStrongHandle(mHandle);
+ if (ipc) ipc->decStrongHandle(binderHandle());
mLock.lock();
Vector<Obituary>* obits = mObituaries;
@@ -442,7 +496,7 @@
mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
}
- if (ipc) ipc->clearDeathNotification(mHandle, this);
+ if (ipc) ipc->clearDeathNotification(binderHandle(), this);
mObituaries = nullptr;
}
mLock.unlock();
@@ -457,9 +511,12 @@
bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/)
{
- ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
+ // RPC binder doesn't currently support inc from weak binders
+ if (CC_UNLIKELY(isRpcBinder())) return false;
+
+ ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, binderHandle());
IPCThreadState* ipc = IPCThreadState::self();
- return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+ return ipc ? ipc->attemptIncStrongHandle(binderHandle()) == NO_ERROR : false;
}
uint32_t BpBinder::getBinderProxyCount(uint32_t uid)
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 349658e..a90bfd2 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -254,7 +254,7 @@
BufferState* bs = ts.states[mIndex].get();
if (bs != nullptr && bs->seq == mSeq) return bs;
- ts.states.editItemAt(mIndex) = new BufferState(mIndex);
+ ts.states.editItemAt(mIndex) = sp<BufferState>::make(mIndex);
bs = ts.states[mIndex].get();
if (bs != nullptr) return bs;
}
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index e4ac4b4..8676955 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -26,6 +26,22 @@
namespace android {
+std::string hexString(const void* bytes, size_t len) {
+ if (bytes == nullptr) return "<null>";
+
+ const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
+ const char chars[] = "0123456789abcdef";
+ std::string result;
+ result.resize(len * 2);
+
+ for (size_t i = 0; i < len; i++) {
+ result[2 * i] = chars[bytes8[i] >> 4];
+ result[2 * i + 1] = chars[bytes8[i] & 0xf];
+ }
+
+ return result;
+}
+
// ---------------------------------------------------------------------
static const char indentStr[] =
diff --git a/libs/binder/Debug.h b/libs/binder/Debug.h
index ac71e00..7ca087e 100644
--- a/libs/binder/Debug.h
+++ b/libs/binder/Debug.h
@@ -17,13 +17,13 @@
#pragma once
#include <stdint.h>
-#include <sys/cdefs.h>
#include <sys/types.h>
+#include <string>
namespace android {
// ---------------------------------------------------------------------------
-__BEGIN_DECLS
+std::string hexString(const void* data, size_t size);
const char* stringForIndent(int32_t indentLevel);
@@ -37,10 +37,7 @@
size_t alignment=0, bool cArrayStyle=false,
debugPrintFunc func = nullptr, void* cookie = nullptr);
-
-ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf);
-
-__END_DECLS
+extern "C" ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf);
// ---------------------------------------------------------------------------
} // namespace android
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index d0085df..0de804c 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/IBatteryStats.h>
+#include <batterystats/IBatteryStats.h>
#include <utils/Log.h>
#include <binder/Parcel.h>
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
index b19004d..2780bd4 100644
--- a/libs/binder/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -33,14 +33,14 @@
sp<IBinder> IInterface::asBinder(const IInterface* iface)
{
if (iface == nullptr) return nullptr;
- return const_cast<IInterface*>(iface)->onAsBinder();
+ return sp<IBinder>::fromExisting(const_cast<IInterface*>(iface)->onAsBinder());
}
// static
sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
{
if (iface == nullptr) return nullptr;
- return iface->onAsBinder();
+ return sp<IBinder>::fromExisting(iface->onAsBinder());
}
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
deleted file mode 100644
index f5fa817..0000000
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 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 <binder/IMediaResourceMonitor.h>
-#include <binder/Parcel.h>
-#include <utils/Errors.h>
-#include <sys/types.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpMediaResourceMonitor : public BpInterface<IMediaResourceMonitor> {
-public:
- explicit BpMediaResourceMonitor(const sp<IBinder>& impl)
- : BpInterface<IMediaResourceMonitor>(impl) {}
-
- virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaResourceMonitor::getInterfaceDescriptor());
- data.writeInt32(pid);
- data.writeInt32(type);
- remote()->transact(NOTIFY_RESOURCE_GRANTED, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor")
-
-// ----------------------------------------------------------------------
-
-// NOLINTNEXTLINE(google-default-arguments)
-status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags) {
- switch(code) {
- case NOTIFY_RESOURCE_GRANTED: {
- CHECK_INTERFACE(IMediaResourceMonitor, data, reply);
- int32_t pid = data.readInt32();
- const int32_t type = data.readInt32();
- notifyResourceGranted(/*in*/ pid, /*in*/ type);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-// ----------------------------------------------------------------------
-
-} // namespace android
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index cca8f81..bd974b0 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -68,7 +68,7 @@
// TODO: Reimplemement based on standard C++ container?
};
-static sp<HeapCache> gHeapCache = new HeapCache();
+static sp<HeapCache> gHeapCache = sp<HeapCache>::make();
/******************************************************************************/
@@ -288,7 +288,7 @@
int32_t heapId = mHeapId.load(memory_order_acquire);
if (heapId == -1) {
sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this)));
- sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
+ sp<BpMemoryHeap> heap = sp<BpMemoryHeap>::cast(find_heap(binder));
heap->assertReallyMapped();
if (heap->mBase != MAP_FAILED) {
Mutex::Autolock _l(mLock);
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 79a11d2..6fb1227 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -90,6 +90,8 @@
"BR_DEAD_BINDER",
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
"BR_FAILED_REPLY",
+ "BR_FROZEN_REPLY",
+ "BR_ONEWAY_SPAM_SUSPECT",
"BR_TRANSACTION_SEC_CTX",
};
@@ -689,6 +691,8 @@
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
+ LOG_ALWAYS_FATAL_IF(data.isForRpc(), "Parcel constructed for RPC, but being used with binder.");
+
status_t err;
flags |= TF_ACCEPT_FDS;
@@ -892,6 +896,11 @@
}
switch (cmd) {
+ case BR_ONEWAY_SPAM_SUSPECT:
+ ALOGE("Process seems to be sending too many oneway calls.");
+ CallStack::logStack("oneway spamming", CallStack::getCurrent().get(),
+ ANDROID_LOG_ERROR);
+ [[fallthrough]];
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index 570edb9..d26754e 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/IProcessInfoService.h>
+#include <processinfo/IProcessInfoService.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <sys/types.h>
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index ca067e2..f684cf6 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -75,6 +75,7 @@
sp<IBinder> waitForService(const String16& name16) override;
bool isDeclared(const String16& name) override;
Vector<String16> getDeclaredInstances(const String16& interface) override;
+ std::optional<String16> updatableViaApex(const String16& name) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
@@ -102,7 +103,7 @@
}
}
- gDefaultServiceManager = new ServiceManagerShim(sm);
+ gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
});
return gDefaultServiceManager;
@@ -324,7 +325,7 @@
}
if (out != nullptr) return out;
- sp<Waiter> waiter = new Waiter;
+ sp<Waiter> waiter = sp<Waiter>::make();
if (!mTheRealServiceManager->registerForNotifications(
name, waiter).isOk()) {
return nullptr;
@@ -388,4 +389,12 @@
return res;
}
+std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
+ std::optional<std::string> declared;
+ if (!mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared).isOk()) {
+ return std::nullopt;
+ }
+ return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
+}
+
} // namespace android
diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp
deleted file mode 100644
index 4edc493..0000000
--- a/libs/binder/IpPrefix.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2015 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 LOG_TAG "IpPrefix"
-
-#include <binder/IpPrefix.h>
-#include <vector>
-
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-#include <log/log.h>
-#include <utils/Errors.h>
-
-using android::BAD_VALUE;
-using android::NO_ERROR;
-using android::Parcel;
-using android::status_t;
-
-namespace android {
-
-namespace net {
-
-#define RETURN_IF_FAILED(calledOnce) \
- { \
- status_t returnStatus = calledOnce; \
- if (returnStatus) { \
- ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
- return returnStatus; \
- } \
- }
-
-status_t IpPrefix::writeToParcel(Parcel* parcel) const {
- /*
- * Keep implementation in sync with writeToParcel() in
- * frameworks/base/core/java/android/net/IpPrefix.java.
- */
- std::vector<uint8_t> byte_vector;
-
- if (mIsIpv6) {
- const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&mUnion.mIn6Addr);
- byte_vector.insert(byte_vector.end(), bytes, bytes+sizeof(mUnion.mIn6Addr));
- } else {
- const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&mUnion.mInAddr);
- byte_vector.insert(byte_vector.end(), bytes, bytes+sizeof(mUnion.mIn6Addr));
- }
-
- RETURN_IF_FAILED(parcel->writeByteVector(byte_vector));
- RETURN_IF_FAILED(parcel->writeInt32(static_cast<int32_t>(mPrefixLength)));
-
- return NO_ERROR;
-}
-
-status_t IpPrefix::readFromParcel(const Parcel* parcel) {
- /*
- * Keep implementation in sync with readFromParcel() in
- * frameworks/base/core/java/android/net/IpPrefix.java.
- */
- std::vector<uint8_t> byte_vector;
-
- RETURN_IF_FAILED(parcel->readByteVector(&byte_vector));
- RETURN_IF_FAILED(parcel->readInt32(&mPrefixLength));
-
- if (byte_vector.size() == 16) {
- mIsIpv6 = true;
- memcpy((void*)&mUnion.mIn6Addr, &byte_vector[0], sizeof(mUnion.mIn6Addr));
-
- } else if (byte_vector.size() == 4) {
- mIsIpv6 = false;
- memcpy((void*)&mUnion.mInAddr, &byte_vector[0], sizeof(mUnion.mInAddr));
-
- } else {
- ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
- return BAD_VALUE;
- }
-
- return NO_ERROR;
-}
-
-const struct in6_addr& IpPrefix::getAddressAsIn6Addr() const
-{
- return mUnion.mIn6Addr;
-}
-
-const struct in_addr& IpPrefix::getAddressAsInAddr() const
-{
- return mUnion.mInAddr;
-}
-
-bool IpPrefix::getAddressAsIn6Addr(struct in6_addr* addr) const
-{
- if (isIpv6()) {
- *addr = mUnion.mIn6Addr;
- return true;
- }
- return false;
-}
-
-bool IpPrefix::getAddressAsInAddr(struct in_addr* addr) const
-{
- if (isIpv4()) {
- *addr = mUnion.mInAddr;
- return true;
- }
- return false;
-}
-
-bool IpPrefix::isIpv6() const
-{
- return mIsIpv6;
-}
-
-bool IpPrefix::isIpv4() const
-{
- return !mIsIpv6;
-}
-
-int32_t IpPrefix::getPrefixLength() const
-{
- return mPrefixLength;
-}
-
-void IpPrefix::setAddress(const struct in6_addr& addr)
-{
- mUnion.mIn6Addr = addr;
- mIsIpv6 = true;
-}
-
-void IpPrefix::setAddress(const struct in_addr& addr)
-{
- mUnion.mInAddr = addr;
- mIsIpv6 = false;
-}
-
-void IpPrefix::setPrefixLength(int32_t prefix)
-{
- mPrefixLength = prefix;
-}
-
-bool operator==(const IpPrefix& lhs, const IpPrefix& rhs)
-{
- if (lhs.mIsIpv6 != rhs.mIsIpv6) {
- return false;
- }
-
- if (lhs.mPrefixLength != rhs.mPrefixLength) {
- return false;
- }
-
- if (lhs.mIsIpv6) {
- return 0 == memcmp(lhs.mUnion.mIn6Addr.s6_addr, rhs.mUnion.mIn6Addr.s6_addr, sizeof(struct in6_addr));
- }
-
- return 0 == memcmp(&lhs.mUnion.mInAddr, &rhs.mUnion.mInAddr, sizeof(struct in_addr));
-}
-
-} // namespace net
-
-} // namespace android
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index f96b6bb..b503beb 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -129,7 +129,9 @@
}
if (!reRegister) {
- if(!manager->registerClientCallback(name, service, this).isOk()) {
+ if (!manager->registerClientCallback(name, service,
+ sp<android::os::IClientCallback>::fromExisting(this))
+ .isOk()) {
ALOGE("Failed to add client callback for service %s", name.c_str());
return false;
}
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index b46b3e8..c4475c7 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -228,10 +228,8 @@
// ----------------------------------------------------------------------------
MemoryDealer::MemoryDealer(size_t size, const char* name, uint32_t flags)
- : mHeap(new MemoryHeapBase(size, flags, name)),
- mAllocator(new SimpleBestFitAllocator(size))
-{
-}
+ : mHeap(sp<MemoryHeapBase>::make(size, flags, name)),
+ mAllocator(new SimpleBestFitAllocator(size)) {}
MemoryDealer::~MemoryDealer()
{
@@ -243,7 +241,7 @@
sp<IMemory> memory;
const ssize_t offset = allocator()->allocate(size);
if (offset >= 0) {
- memory = new Allocation(this, heap(), offset, size);
+ memory = sp<Allocation>::make(sp<MemoryDealer>::fromExisting(this), heap(), offset, size);
}
return memory;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 1a4ede1..98ca829 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -41,13 +41,15 @@
#include <binder/TextOutput.h>
#include <cutils/ashmem.h>
+#include <cutils/compiler.h>
#include <utils/Flattenable.h>
#include <utils/Log.h>
-#include <utils/misc.h>
-#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/misc.h>
#include <private/binder/binder_module.h>
+#include "RpcState.h"
#include "Static.h"
#include "Utils.h"
@@ -191,6 +193,22 @@
status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
+ if (isForRpc()) {
+ if (binder) {
+ status_t status = writeInt32(1); // non-null
+ if (status != OK) return status;
+ RpcAddress address = RpcAddress::zero();
+ status = mConnection->state()->onBinderLeaving(mConnection, binder, &address);
+ if (status != OK) return status;
+ status = address.writeToParcel(this);
+ if (status != OK) return status;
+ } else {
+ status_t status = writeInt32(0); // null
+ if (status != OK) return status;
+ }
+ return finishFlattenBinder(binder);
+ }
+
flat_binder_object obj;
obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
@@ -205,8 +223,13 @@
BpBinder *proxy = binder->remoteBinder();
if (proxy == nullptr) {
ALOGE("null proxy");
+ } else {
+ if (proxy->isRpcBinder()) {
+ ALOGE("Sending a socket binder over RPC is prohibited");
+ return INVALID_OPERATION;
+ }
}
- const int32_t handle = proxy ? proxy->getPrivateAccessorForHandle().handle() : 0;
+ const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
obj.hdr.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
@@ -245,12 +268,33 @@
status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
+ if (isForRpc()) {
+ LOG_ALWAYS_FATAL_IF(mConnection == nullptr,
+ "RpcConnection required to read from remote parcel");
+
+ int32_t isNull;
+ status_t status = readInt32(&isNull);
+ if (status != OK) return status;
+
+ sp<IBinder> binder;
+
+ if (isNull & 1) {
+ auto addr = RpcAddress::zero();
+ status_t status = addr.readFromParcel(*this);
+ if (status != OK) return status;
+ binder = mConnection->state()->onBinderEntering(mConnection, addr);
+ }
+
+ return finishUnflattenBinder(binder, out);
+ }
+
const flat_binder_object* flat = readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER: {
- sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+ sp<IBinder> binder =
+ sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie));
return finishUnflattenBinder(binder, out);
}
case BINDER_TYPE_HANDLE: {
@@ -375,6 +419,11 @@
status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
{
+ if (parcel->isForRpc() != isForRpc()) {
+ ALOGE("Cannot append Parcel of one format to another.");
+ return BAD_TYPE;
+ }
+
status_t err;
const uint8_t *data = parcel->mData;
const binder_size_t *objects = parcel->mObjects;
@@ -511,6 +560,26 @@
mDeallocZero = true;
}
+void Parcel::markForBinder(const sp<IBinder>& binder) {
+ LOG_ALWAYS_FATAL_IF(mData != nullptr, "format must be set before data is written");
+
+ if (binder && binder->remoteBinder() && binder->remoteBinder()->isRpcBinder()) {
+ markForRpc(binder->remoteBinder()->getPrivateAccessorForId().rpcConnection());
+ }
+}
+
+void Parcel::markForRpc(const sp<RpcConnection>& connection) {
+ LOG_ALWAYS_FATAL_IF(mData != nullptr && mOwner == nullptr,
+ "format must be set before data is written OR on IPC data");
+
+ LOG_ALWAYS_FATAL_IF(connection == nullptr, "markForRpc requires connection");
+ mConnection = connection;
+}
+
+bool Parcel::isForRpc() const {
+ return mConnection != nullptr;
+}
+
void Parcel::updateWorkSourceRequestHeaderPosition() const {
// Only update the request headers once. We only want to point
// to the first headers read/written.
@@ -533,12 +602,14 @@
}
status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
- const IPCThreadState* threadState = IPCThreadState::self();
- writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
- updateWorkSourceRequestHeaderPosition();
- writeInt32(threadState->shouldPropagateWorkSource() ?
- threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
- writeInt32(kHeader);
+ if (CC_LIKELY(!isForRpc())) {
+ const IPCThreadState* threadState = IPCThreadState::self();
+ writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+ updateWorkSourceRequestHeaderPosition();
+ writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid()
+ : IPCThreadState::kUnsetWorkSource);
+ writeInt32(kHeader);
+ }
// currently the interface identification token is just its name as a string
return writeString16(str, len);
@@ -585,31 +656,34 @@
size_t len,
IPCThreadState* threadState) const
{
- // StrictModePolicy.
- int32_t strictPolicy = readInt32();
- if (threadState == nullptr) {
- threadState = IPCThreadState::self();
+ if (CC_LIKELY(!isForRpc())) {
+ // StrictModePolicy.
+ int32_t strictPolicy = readInt32();
+ if (threadState == nullptr) {
+ threadState = IPCThreadState::self();
+ }
+ if ((threadState->getLastTransactionBinderFlags() & IBinder::FLAG_ONEWAY) != 0) {
+ // For one-way calls, the callee is running entirely
+ // disconnected from the caller, so disable StrictMode entirely.
+ // Not only does disk/network usage not impact the caller, but
+ // there's no way to communicate back violations anyway.
+ threadState->setStrictModePolicy(0);
+ } else {
+ threadState->setStrictModePolicy(strictPolicy);
+ }
+ // WorkSource.
+ updateWorkSourceRequestHeaderPosition();
+ int32_t workSource = readInt32();
+ threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
+ // vendor header
+ int32_t header = readInt32();
+ if (header != kHeader) {
+ ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader,
+ header);
+ return false;
+ }
}
- if ((threadState->getLastTransactionBinderFlags() &
- IBinder::FLAG_ONEWAY) != 0) {
- // For one-way calls, the callee is running entirely
- // disconnected from the caller, so disable StrictMode entirely.
- // Not only does disk/network usage not impact the caller, but
- // there's no way to commuicate back any violations anyway.
- threadState->setStrictModePolicy(0);
- } else {
- threadState->setStrictModePolicy(strictPolicy);
- }
- // WorkSource.
- updateWorkSourceRequestHeaderPosition();
- int32_t workSource = readInt32();
- threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
- // vendor header
- int32_t header = readInt32();
- if (header != kHeader) {
- ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header);
- return false;
- }
+
// Interface descriptor.
size_t parcel_interface_len;
const char16_t* parcel_interface = readString16Inplace(&parcel_interface_len);
@@ -1070,6 +1144,11 @@
status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
{
+ if (isForRpc()) {
+ ALOGE("Cannot write file descriptor to remote binder.");
+ return BAD_TYPE;
+ }
+
flat_binder_object obj;
obj.hdr.type = BINDER_TYPE_FD;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
@@ -2032,6 +2111,9 @@
void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
const binder_size_t* objects, size_t objectsCount, release_func relFunc)
{
+ // this code uses 'mOwner == nullptr' to understand whether it owns memory
+ LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function");
+
freeData();
mData = const_cast<uint8_t*>(data);
@@ -2413,6 +2495,7 @@
mDataPos = 0;
ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
+ mConnection = nullptr;
mObjects = nullptr;
mObjectsSize = 0;
mObjectsCapacity = 0;
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index f75141e..0fb954a 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/ProcessInfoService.h>
+#include <processinfo/ProcessInfoService.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index c38249e..a2efb1c 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -43,6 +43,7 @@
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 15
+#define DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION 1
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
@@ -105,7 +106,7 @@
}
std::lock_guard<std::mutex> l(gProcessMutex);
- gProcess = new ProcessState(driver);
+ gProcess = sp<ProcessState>::make(driver);
});
if (requireDefault) {
@@ -205,10 +206,12 @@
//
// Returns -1 in case of failure, otherwise the strong reference count.
ssize_t ProcessState::getStrongRefCountForNode(const sp<BpBinder>& binder) {
+ if (binder->isRpcBinder()) return -1;
+
binder_node_info_for_ref info;
memset(&info, 0, sizeof(binder_node_info_for_ref));
- info.handle = binder->getPrivateAccessorForHandle().handle();
+ info.handle = binder->getPrivateAccessorForId().binderHandle();
status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
@@ -297,8 +300,8 @@
return nullptr;
}
- b = BpBinder::create(handle);
- e->binder = b;
+ sp<BpBinder> b = BpBinder::create(handle);
+ e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
@@ -338,7 +341,7 @@
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
- sp<Thread> t = new PoolThread(isMain);
+ sp<Thread> t = sp<PoolThread>::make(isMain);
t->run(name.string());
}
}
@@ -356,6 +359,15 @@
return result;
}
+status_t ProcessState::enableOnewaySpamDetection(bool enable) {
+ uint32_t enableDetection = enable ? 1 : 0;
+ if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
+ ALOGI("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ return -errno;
+ }
+ return NO_ERROR;
+}
+
void ProcessState::giveThreadPoolName() {
androidSetThreadName( makeBinderThreadName().string() );
}
@@ -386,6 +398,11 @@
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
+ uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
+ result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
+ if (result == -1) {
+ ALOGI("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+ }
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
new file mode 100644
index 0000000..5c32320
--- /dev/null
+++ b/libs/binder/RpcAddress.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/RpcAddress.h>
+
+#include <binder/Parcel.h>
+
+#include "Debug.h"
+#include "RpcState.h"
+#include "RpcWireFormat.h"
+
+namespace android {
+
+RpcAddress RpcAddress::zero() {
+ return RpcAddress();
+}
+
+bool RpcAddress::isZero() const {
+ RpcWireAddress ZERO{0};
+ return memcmp(mRawAddr.get(), &ZERO, sizeof(RpcWireAddress)) == 0;
+}
+
+static void ReadRandomBytes(uint8_t* buf, size_t len) {
+ int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ if (fd == -1) {
+ ALOGE("%s: cannot read /dev/urandom", __func__);
+ return;
+ }
+
+ size_t n;
+ while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
+ len -= n;
+ buf += n;
+ }
+ if (len > 0) {
+ ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
+ }
+ close(fd);
+}
+
+RpcAddress RpcAddress::unique() {
+ RpcAddress ret;
+ ReadRandomBytes((uint8_t*)ret.mRawAddr.get(), sizeof(RpcWireAddress));
+ LOG_RPC_DETAIL("Creating new address: %s", ret.toString().c_str());
+ return ret;
+}
+
+RpcAddress RpcAddress::fromRawEmbedded(const RpcWireAddress* raw) {
+ RpcAddress addr;
+ memcpy(addr.mRawAddr.get(), raw, sizeof(RpcWireAddress));
+ return addr;
+}
+
+const RpcWireAddress& RpcAddress::viewRawEmbedded() const {
+ return *mRawAddr.get();
+}
+
+bool RpcAddress::operator<(const RpcAddress& rhs) const {
+ return std::memcmp(mRawAddr.get(), rhs.mRawAddr.get(), sizeof(RpcWireAddress)) < 0;
+}
+
+std::string RpcAddress::toString() const {
+ return hexString(mRawAddr.get(), sizeof(RpcWireAddress));
+}
+
+status_t RpcAddress::writeToParcel(Parcel* parcel) const {
+ return parcel->write(mRawAddr.get(), sizeof(RpcWireAddress));
+}
+
+status_t RpcAddress::readFromParcel(const Parcel& parcel) {
+ return parcel.read(mRawAddr.get(), sizeof(RpcWireAddress));
+}
+
+RpcAddress::~RpcAddress() {}
+RpcAddress::RpcAddress() : mRawAddr(std::make_shared<RpcWireAddress>()) {}
+
+} // namespace android
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
new file mode 100644
index 0000000..1388a80
--- /dev/null
+++ b/libs/binder/RpcConnection.cpp
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RpcConnection"
+
+#include <binder/RpcConnection.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <string_view>
+
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <utils/String8.h>
+
+#include "RpcState.h"
+#include "RpcWireFormat.h"
+
+#ifdef __GLIBC__
+extern "C" pid_t gettid();
+#endif
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif
+
+namespace android {
+
+using base::unique_fd;
+using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
+
+RpcConnection::SocketAddress::~SocketAddress() {}
+
+RpcConnection::RpcConnection() {
+ LOG_RPC_DETAIL("RpcConnection created %p", this);
+
+ mState = std::make_unique<RpcState>();
+}
+RpcConnection::~RpcConnection() {
+ LOG_RPC_DETAIL("RpcConnection destroyed %p", this);
+
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ LOG_ALWAYS_FATAL_IF(mServers.size() != 0,
+ "Should not be able to destroy a connection with servers in use.");
+}
+
+sp<RpcConnection> RpcConnection::make() {
+ return sp<RpcConnection>::make();
+}
+
+class UnixSocketAddress : public RpcConnection::SocketAddress {
+public:
+ explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
+ unsigned int pathLen = strlen(path) + 1;
+ LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
+ pathLen, path);
+ memcpy(mAddr.sun_path, path, pathLen);
+ }
+ virtual ~UnixSocketAddress() {}
+ std::string toString() const override {
+ return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
+ mAddr.sun_path)
+ .c_str();
+ }
+ const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+ size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+ sockaddr_un mAddr;
+};
+
+bool RpcConnection::setupUnixDomainServer(const char* path) {
+ return setupSocketServer(UnixSocketAddress(path));
+}
+
+bool RpcConnection::addUnixDomainClient(const char* path) {
+ return addSocketClient(UnixSocketAddress(path));
+}
+
+#ifdef __BIONIC__
+
+class VsockSocketAddress : public RpcConnection::SocketAddress {
+public:
+ VsockSocketAddress(unsigned int cid, unsigned int port)
+ : mAddr({
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ .svm_cid = cid,
+ }) {}
+ virtual ~VsockSocketAddress() {}
+ std::string toString() const override {
+ return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
+ }
+ const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+ size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+ sockaddr_vm mAddr;
+};
+
+bool RpcConnection::setupVsockServer(unsigned int port) {
+ // realizing value w/ this type at compile time to avoid ubsan abort
+ constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
+
+ return setupSocketServer(VsockSocketAddress(kAnyCid, port));
+}
+
+bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
+ return addSocketClient(VsockSocketAddress(cid, port));
+}
+
+#endif // __BIONIC__
+
+class SocketAddressImpl : public RpcConnection::SocketAddress {
+public:
+ SocketAddressImpl(const sockaddr* addr, size_t size, const String8& desc)
+ : mAddr(addr), mSize(size), mDesc(desc) {}
+ [[nodiscard]] std::string toString() const override {
+ return std::string(mDesc.c_str(), mDesc.size());
+ }
+ [[nodiscard]] const sockaddr* addr() const override { return mAddr; }
+ [[nodiscard]] size_t addrSize() const override { return mSize; }
+ void set(const sockaddr* addr, size_t size) {
+ mAddr = addr;
+ mSize = size;
+ }
+
+private:
+ const sockaddr* mAddr = nullptr;
+ size_t mSize = 0;
+ String8 mDesc;
+};
+
+AddrInfo GetAddrInfo(const char* addr, unsigned int port) {
+ addrinfo hint{
+ .ai_flags = 0,
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = 0,
+ };
+ addrinfo* aiStart = nullptr;
+ if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
+ ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
+ return AddrInfo(nullptr, nullptr);
+ }
+ if (aiStart == nullptr) {
+ ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
+ return AddrInfo(nullptr, nullptr);
+ }
+ return AddrInfo(aiStart, &freeaddrinfo);
+}
+
+bool RpcConnection::setupInetServer(unsigned int port) {
+ auto aiStart = GetAddrInfo("127.0.0.1", port);
+ if (aiStart == nullptr) return false;
+ SocketAddressImpl socketAddress(nullptr, 0, String8::format("127.0.0.1:%u", port));
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ socketAddress.set(ai->ai_addr, ai->ai_addrlen);
+ if (setupSocketServer(socketAddress)) return true;
+ }
+ ALOGE("None of the socket address resolved for 127.0.0.1:%u can be set up as inet server.",
+ port);
+ return false;
+}
+
+bool RpcConnection::addInetClient(const char* addr, unsigned int port) {
+ auto aiStart = GetAddrInfo(addr, port);
+ if (aiStart == nullptr) return false;
+ SocketAddressImpl socketAddress(nullptr, 0, String8::format("%s:%u", addr, port));
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ socketAddress.set(ai->ai_addr, ai->ai_addrlen);
+ if (addSocketClient(socketAddress)) return true;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
+ return false;
+}
+
+bool RpcConnection::addNullDebuggingClient() {
+ unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
+
+ if (serverFd == -1) {
+ ALOGE("Could not connect to /dev/null: %s", strerror(errno));
+ return false;
+ }
+
+ addClient(std::move(serverFd));
+ return true;
+}
+
+sp<IBinder> RpcConnection::getRootObject() {
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
+ return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this));
+}
+
+status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this),
+ (flags & IBinder::FLAG_ONEWAY) ? SocketUse::CLIENT_ASYNC
+ : SocketUse::CLIENT);
+ return state()->transact(socket.fd(), address, code, data,
+ sp<RpcConnection>::fromExisting(this), reply, flags);
+}
+
+status_t RpcConnection::sendDecStrong(const RpcAddress& address) {
+ ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT_REFCOUNT);
+ return state()->sendDecStrong(socket.fd(), address);
+}
+
+void RpcConnection::join() {
+ // TODO(b/185167543): do this dynamically, instead of from a static number
+ // of threads
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
+ if (clientFd < 0) {
+ // If this log becomes confusing, should save more state from setupUnixDomainServer
+ // in order to output here.
+ ALOGE("Could not accept4 socket: %s", strerror(errno));
+ return;
+ }
+
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+ // must be registered to allow arbitrary client code executing commands to
+ // be able to do nested calls (we can't only read from it)
+ sp<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd));
+
+ while (true) {
+ status_t error =
+ state()->getAndExecuteCommand(socket->fd, sp<RpcConnection>::fromExisting(this));
+
+ if (error != OK) {
+ ALOGI("Binder socket thread closing w/ status %s", statusToString(error).c_str());
+ break;
+ }
+ }
+
+ LOG_ALWAYS_FATAL_IF(!removeServerSocket(socket),
+ "bad state: socket object guaranteed to be in list");
+}
+
+void RpcConnection::setForServer(const wp<RpcServer>& server) {
+ mForServer = server;
+}
+
+wp<RpcServer> RpcConnection::server() {
+ return mForServer;
+}
+
+bool RpcConnection::setupSocketServer(const SocketAddress& addr) {
+ LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");
+
+ unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ if (serverFd == -1) {
+ ALOGE("Could not create socket: %s", strerror(errno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+ int savedErrno = errno;
+ ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ mServer = std::move(serverFd);
+ return true;
+}
+
+bool RpcConnection::addSocketClient(const SocketAddress& addr) {
+ unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ if (serverFd == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+ return false;
+ }
+
+ LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
+
+ addClient(std::move(serverFd));
+ return true;
+}
+
+void RpcConnection::addClient(unique_fd&& fd) {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
+ connection->fd = std::move(fd);
+ mClients.push_back(connection);
+}
+
+sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
+ connection->fd = std::move(fd);
+ connection->exclusiveTid = gettid();
+ mServers.push_back(connection);
+
+ return connection;
+}
+
+bool RpcConnection::removeServerSocket(const sp<ConnectionSocket>& socket) {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ if (auto it = std::find(mServers.begin(), mServers.end(), socket); it != mServers.end()) {
+ mServers.erase(it);
+ return true;
+ }
+ return false;
+}
+
+RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connection, SocketUse use)
+ : mConnection(connection) {
+ pid_t tid = gettid();
+ std::unique_lock<std::mutex> _l(mConnection->mSocketMutex);
+
+ mConnection->mWaitingThreads++;
+ while (true) {
+ sp<ConnectionSocket> exclusive;
+ sp<ConnectionSocket> available;
+
+ // CHECK FOR DEDICATED CLIENT SOCKET
+ //
+ // A server/looper should always use a dedicated connection if available
+ findSocket(tid, &exclusive, &available, mConnection->mClients, mConnection->mClientsOffset);
+
+ // WARNING: this assumes a server cannot request its client to send
+ // a transaction, as mServers is excluded below.
+ //
+ // Imagine we have more than one thread in play, and a single thread
+ // sends a synchronous, then an asynchronous command. Imagine the
+ // asynchronous command is sent on the first client socket. Then, if
+ // we naively send a synchronous command to that same socket, the
+ // thread on the far side might be busy processing the asynchronous
+ // command. So, we move to considering the second available thread
+ // for subsequent calls.
+ if (use == SocketUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
+ mConnection->mClientsOffset =
+ (mConnection->mClientsOffset + 1) % mConnection->mClients.size();
+ }
+
+ // USE SERVING SOCKET (for nested transaction)
+ //
+ // asynchronous calls cannot be nested
+ if (use != SocketUse::CLIENT_ASYNC) {
+ // server sockets are always assigned to a thread
+ findSocket(tid, &exclusive, nullptr /*available*/, mConnection->mServers,
+ 0 /* index hint */);
+ }
+
+ // if our thread is already using a connection, prioritize using that
+ if (exclusive != nullptr) {
+ mSocket = exclusive;
+ mReentrant = true;
+ break;
+ } else if (available != nullptr) {
+ mSocket = available;
+ mSocket->exclusiveTid = tid;
+ break;
+ }
+
+ // in regular binder, this would usually be a deadlock :)
+ LOG_ALWAYS_FATAL_IF(mConnection->mClients.size() == 0,
+ "Not a client of any connection. You must create a connection to an "
+ "RPC server to make any non-nested (e.g. oneway or on another thread) "
+ "calls.");
+
+ LOG_RPC_DETAIL("No available connection (have %zu clients and %zu servers). Waiting...",
+ mConnection->mClients.size(), mConnection->mServers.size());
+ mConnection->mSocketCv.wait(_l);
+ }
+ mConnection->mWaitingThreads--;
+}
+
+void RpcConnection::ExclusiveSocket::findSocket(pid_t tid, sp<ConnectionSocket>* exclusive,
+ sp<ConnectionSocket>* available,
+ std::vector<sp<ConnectionSocket>>& sockets,
+ size_t socketsIndexHint) {
+ LOG_ALWAYS_FATAL_IF(sockets.size() > 0 && socketsIndexHint >= sockets.size(),
+ "Bad index %zu >= %zu", socketsIndexHint, sockets.size());
+
+ if (*exclusive != nullptr) return; // consistent with break below
+
+ for (size_t i = 0; i < sockets.size(); i++) {
+ sp<ConnectionSocket>& socket = sockets[(i + socketsIndexHint) % sockets.size()];
+
+ // take first available connection (intuition = caching)
+ if (available && *available == nullptr && socket->exclusiveTid == std::nullopt) {
+ *available = socket;
+ continue;
+ }
+
+ // though, prefer to take connection which is already inuse by this thread
+ // (nested transactions)
+ if (exclusive && socket->exclusiveTid == tid) {
+ *exclusive = socket;
+ break; // consistent with return above
+ }
+ }
+}
+
+RpcConnection::ExclusiveSocket::~ExclusiveSocket() {
+ // reentrant use of a connection means something less deep in the call stack
+ // is using this fd, and it retains the right to it. So, we don't give up
+ // exclusive ownership, and no thread is freed.
+ if (!mReentrant) {
+ std::unique_lock<std::mutex> _l(mConnection->mSocketMutex);
+ mSocket->exclusiveTid = std::nullopt;
+ if (mConnection->mWaitingThreads > 0) {
+ _l.unlock();
+ mConnection->mSocketCv.notify_one();
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
new file mode 100644
index 0000000..1fa37ba
--- /dev/null
+++ b/libs/binder/RpcServer.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RpcServer"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <log/log.h>
+#include "RpcState.h"
+
+#include "RpcWireFormat.h"
+
+namespace android {
+
+using base::unique_fd;
+
+RpcServer::RpcServer() {}
+RpcServer::~RpcServer() {}
+
+sp<RpcServer> RpcServer::make() {
+ return sp<RpcServer>::make();
+}
+
+void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
+ mAgreedExperimental = true;
+}
+
+sp<RpcConnection> RpcServer::addClientConnection() {
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+
+ auto connection = RpcConnection::make();
+ connection->setForServer(sp<RpcServer>::fromExisting(this));
+ mConnections.push_back(connection);
+ return connection;
+}
+
+void RpcServer::setRootObject(const sp<IBinder>& binder) {
+ LOG_ALWAYS_FATAL_IF(mRootObject != nullptr, "There can only be one root object");
+ mRootObject = binder;
+}
+
+sp<IBinder> RpcServer::getRootObject() {
+ return mRootObject;
+}
+
+} // namespace android
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
new file mode 100644
index 0000000..d934136
--- /dev/null
+++ b/libs/binder/RpcState.cpp
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RpcState"
+
+#include "RpcState.h"
+
+#include <binder/BpBinder.h>
+#include <binder/RpcServer.h>
+
+#include "Debug.h"
+#include "RpcWireFormat.h"
+
+#include <inttypes.h>
+
+namespace android {
+
+RpcState::RpcState() {}
+RpcState::~RpcState() {}
+
+status_t RpcState::onBinderLeaving(const sp<RpcConnection>& connection, const sp<IBinder>& binder,
+ RpcAddress* outAddress) {
+ bool isRemote = binder->remoteBinder();
+ bool isRpc = isRemote && binder->remoteBinder()->isRpcBinder();
+
+ if (isRpc && binder->remoteBinder()->getPrivateAccessorForId().rpcConnection() != connection) {
+ // We need to be able to send instructions over the socket for how to
+ // connect to a different server, and we also need to let the host
+ // process know that this is happening.
+ ALOGE("Cannot send binder from unrelated binder RPC connection.");
+ return INVALID_OPERATION;
+ }
+
+ if (isRemote && !isRpc) {
+ // Without additional work, this would have the effect of using this
+ // process to proxy calls from the socket over to the other process, and
+ // it would make those calls look like they come from us (not over the
+ // sockets). In order to make this work transparently like binder, we
+ // would instead need to send instructions over the socket for how to
+ // connect to the host process, and we also need to let the host process
+ // know this was happening.
+ ALOGE("Cannot send binder proxy %p over sockets", binder.get());
+ return INVALID_OPERATION;
+ }
+
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+
+ // TODO(b/182939933): maybe move address out of BpBinder, and keep binder->address map
+ // in RpcState
+ for (auto& [addr, node] : mNodeForAddress) {
+ if (binder == node.binder) {
+ if (isRpc) {
+ const RpcAddress& actualAddr =
+ binder->remoteBinder()->getPrivateAccessorForId().rpcAddress();
+ // TODO(b/182939933): this is only checking integrity of data structure
+ // a different data structure doesn't need this
+ LOG_ALWAYS_FATAL_IF(addr < actualAddr, "Address mismatch");
+ LOG_ALWAYS_FATAL_IF(actualAddr < addr, "Address mismatch");
+ }
+ node.timesSent++;
+ node.sentRef = binder; // might already be set
+ *outAddress = addr;
+ return OK;
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(isRpc, "RPC binder must have known address at this point");
+
+ auto&& [it, inserted] = mNodeForAddress.insert({RpcAddress::unique(),
+ BinderNode{
+ .binder = binder,
+ .timesSent = 1,
+ .sentRef = binder,
+ }});
+ // TODO(b/182939933): better organization could avoid needing this log
+ LOG_ALWAYS_FATAL_IF(!inserted);
+
+ *outAddress = it->first;
+ return OK;
+}
+
+sp<IBinder> RpcState::onBinderEntering(const sp<RpcConnection>& connection,
+ const RpcAddress& address) {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+
+ if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
+ sp<IBinder> binder = it->second.binder.promote();
+
+ // implicitly have strong RPC refcount, since we received this binder
+ it->second.timesRecd++;
+
+ _l.unlock();
+
+ // We have timesRecd RPC refcounts, but we only need to hold on to one
+ // when we keep the object. All additional dec strongs are sent
+ // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
+ (void)connection->sendDecStrong(address);
+
+ return binder;
+ }
+
+ auto&& [it, inserted] = mNodeForAddress.insert({address, BinderNode{}});
+ LOG_ALWAYS_FATAL_IF(!inserted, "Failed to insert binder when creating proxy");
+
+ // Currently, all binders are assumed to be part of the same connection (no
+ // device global binders in the RPC world).
+ sp<IBinder> binder = BpBinder::create(connection, it->first);
+ it->second.binder = binder;
+ it->second.timesRecd = 1;
+ return binder;
+}
+
+size_t RpcState::countBinders() {
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+ return mNodeForAddress.size();
+}
+
+void RpcState::dump() {
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+ ALOGE("DUMP OF RpcState %p", this);
+ ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size());
+ for (const auto& [address, node] : mNodeForAddress) {
+ sp<IBinder> binder = node.binder.promote();
+
+ const char* desc;
+ if (binder) {
+ if (binder->remoteBinder()) {
+ if (binder->remoteBinder()->isRpcBinder()) {
+ desc = "(rpc binder proxy)";
+ } else {
+ desc = "(binder proxy)";
+ }
+ } else {
+ desc = "(local binder)";
+ }
+ } else {
+ desc = "(null)";
+ }
+
+ ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a:%s type:%s",
+ node.binder.unsafe_get(), node.timesSent, node.timesRecd, address.toString().c_str(),
+ desc);
+ }
+ ALOGE("END DUMP OF RpcState");
+}
+
+void RpcState::terminate() {
+ if (SHOULD_LOG_RPC_DETAIL) {
+ ALOGE("RpcState::terminate()");
+ dump();
+ }
+
+ // if the destructor of a binder object makes another RPC call, then calling
+ // decStrong could deadlock. So, we must hold onto these binders until
+ // mNodeMutex is no longer taken.
+ std::vector<sp<IBinder>> tempHoldBinder;
+
+ {
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+ mTerminated = true;
+ for (auto& [address, node] : mNodeForAddress) {
+ sp<IBinder> binder = node.binder.promote();
+ LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get());
+
+ if (node.sentRef != nullptr) {
+ tempHoldBinder.push_back(node.sentRef);
+ }
+ }
+
+ mNodeForAddress.clear();
+ }
+}
+
+bool RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* data, size_t size) {
+ LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str());
+
+ if (size > std::numeric_limits<ssize_t>::max()) {
+ ALOGE("Cannot send %s at size %zu (too big)", what, size);
+ terminate();
+ return false;
+ }
+
+ ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, MSG_NOSIGNAL));
+
+ if (sent < 0 || sent != static_cast<ssize_t>(size)) {
+ ALOGE("Failed to send %s (sent %zd of %zu bytes) on fd %d, error: %s", what, sent, size,
+ fd.get(), strerror(errno));
+
+ terminate();
+ return false;
+ }
+
+ return true;
+}
+
+bool RpcState::rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size) {
+ if (size > std::numeric_limits<ssize_t>::max()) {
+ ALOGE("Cannot rec %s at size %zu (too big)", what, size);
+ terminate();
+ return false;
+ }
+
+ ssize_t recd = TEMP_FAILURE_RETRY(recv(fd.get(), data, size, MSG_WAITALL | MSG_NOSIGNAL));
+
+ if (recd < 0 || recd != static_cast<ssize_t>(size)) {
+ terminate();
+
+ if (recd == 0 && errno == 0) {
+ LOG_RPC_DETAIL("No more data when trying to read %s on fd %d", what, fd.get());
+ return false;
+ }
+
+ ALOGE("Failed to read %s (received %zd of %zu bytes) on fd %d, error: %s", what, recd, size,
+ fd.get(), strerror(errno));
+ return false;
+ } else {
+ LOG_RPC_DETAIL("Received %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str());
+ }
+
+ return true;
+}
+
+sp<IBinder> RpcState::getRootObject(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection) {
+ Parcel data;
+ data.markForRpc(connection);
+ Parcel reply;
+
+ status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT, data,
+ connection, &reply, 0);
+ if (status != OK) {
+ ALOGE("Error getting root object: %s", statusToString(status).c_str());
+ return nullptr;
+ }
+
+ return reply.readStrongBinder();
+}
+
+status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address, uint32_t code,
+ const Parcel& data, const sp<RpcConnection>& connection, Parcel* reply,
+ uint32_t flags) {
+ uint64_t asyncNumber = 0;
+
+ if (!address.isZero()) {
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
+ auto it = mNodeForAddress.find(address);
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending transact on unknown address %s",
+ address.toString().c_str());
+
+ if (flags & IBinder::FLAG_ONEWAY) {
+ asyncNumber = it->second.asyncNumber++;
+ }
+ }
+
+ if (!data.isForRpc()) {
+ ALOGE("Refusing to send RPC with parcel not crafted for RPC");
+ return BAD_TYPE;
+ }
+
+ if (data.objectsCount() != 0) {
+ ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data);
+ return BAD_TYPE;
+ }
+
+ RpcWireTransaction transaction{
+ .address = address.viewRawEmbedded(),
+ .code = code,
+ .flags = flags,
+ .asyncNumber = asyncNumber,
+ };
+
+ std::vector<uint8_t> transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+ memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction));
+ memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize());
+
+ if (transactionData.size() > std::numeric_limits<uint32_t>::max()) {
+ ALOGE("Transaction size too big %zu", transactionData.size());
+ return BAD_VALUE;
+ }
+
+ RpcWireHeader command{
+ .command = RPC_COMMAND_TRANSACT,
+ .bodySize = static_cast<uint32_t>(transactionData.size()),
+ };
+
+ if (!rpcSend(fd, "transact header", &command, sizeof(command))) {
+ return DEAD_OBJECT;
+ }
+ if (!rpcSend(fd, "command body", transactionData.data(), transactionData.size())) {
+ return DEAD_OBJECT;
+ }
+
+ if (flags & IBinder::FLAG_ONEWAY) {
+ return OK; // do not wait for result
+ }
+
+ LOG_ALWAYS_FATAL_IF(reply == nullptr, "Reply parcel must be used for synchronous transaction.");
+
+ return waitForReply(fd, connection, reply);
+}
+
+static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
+ const binder_size_t* objects, size_t objectsCount) {
+ (void)p;
+ delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
+ (void)dataSize;
+ LOG_ALWAYS_FATAL_IF(objects != nullptr);
+ LOG_ALWAYS_FATAL_IF(objectsCount, 0);
+}
+
+status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+ Parcel* reply) {
+ RpcWireHeader command;
+ while (true) {
+ if (!rpcRec(fd, "command header", &command, sizeof(command))) {
+ return DEAD_OBJECT;
+ }
+
+ if (command.command == RPC_COMMAND_REPLY) break;
+
+ status_t status = processServerCommand(fd, connection, command);
+ if (status != OK) return status;
+ }
+
+ uint8_t* data = new uint8_t[command.bodySize];
+
+ if (!rpcRec(fd, "reply body", data, command.bodySize)) {
+ return DEAD_OBJECT;
+ }
+
+ if (command.bodySize < sizeof(RpcWireReply)) {
+ ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
+ sizeof(RpcWireReply), command.bodySize);
+ terminate();
+ return BAD_VALUE;
+ }
+ RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data);
+ if (rpcReply->status != OK) return rpcReply->status;
+
+ reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
+ nullptr, 0, cleanup_reply_data);
+
+ reply->markForRpc(connection);
+
+ return OK;
+}
+
+status_t RpcState::sendDecStrong(const base::unique_fd& fd, const RpcAddress& addr) {
+ {
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
+ auto it = mNodeForAddress.find(addr);
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending dec strong on unknown address %s",
+ addr.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %s",
+ addr.toString().c_str());
+
+ it->second.timesRecd--;
+ if (it->second.timesRecd == 0 && it->second.timesSent == 0) {
+ mNodeForAddress.erase(it);
+ }
+ }
+
+ RpcWireHeader cmd = {
+ .command = RPC_COMMAND_DEC_STRONG,
+ .bodySize = sizeof(RpcWireAddress),
+ };
+ if (!rpcSend(fd, "dec ref header", &cmd, sizeof(cmd))) return DEAD_OBJECT;
+ if (!rpcSend(fd, "dec ref body", &addr.viewRawEmbedded(), sizeof(RpcWireAddress)))
+ return DEAD_OBJECT;
+ return OK;
+}
+
+status_t RpcState::getAndExecuteCommand(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection) {
+ LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", fd.get());
+
+ RpcWireHeader command;
+ if (!rpcRec(fd, "command header", &command, sizeof(command))) {
+ return DEAD_OBJECT;
+ }
+
+ return processServerCommand(fd, connection, command);
+}
+
+status_t RpcState::processServerCommand(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection,
+ const RpcWireHeader& command) {
+ switch (command.command) {
+ case RPC_COMMAND_TRANSACT:
+ return processTransact(fd, connection, command);
+ case RPC_COMMAND_DEC_STRONG:
+ return processDecStrong(fd, command);
+ }
+
+ // We should always know the version of the opposing side, and since the
+ // RPC-binder-level wire protocol is not self synchronizing, we have no way
+ // to understand where the current command ends and the next one begins. We
+ // also can't consider it a fatal error because this would allow any client
+ // to kill us, so ending the connection for misbehaving client.
+ ALOGE("Unknown RPC command %d - terminating connection", command.command);
+ terminate();
+ return DEAD_OBJECT;
+}
+status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+ const RpcWireHeader& command) {
+ LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
+
+ std::vector<uint8_t> transactionData(command.bodySize);
+ if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) {
+ return DEAD_OBJECT;
+ }
+
+ return processTransactInternal(fd, connection, std::move(transactionData));
+}
+
+static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize,
+ const binder_size_t* objects, size_t objectsCount) {
+ (void)p;
+ (void)data;
+ (void)dataSize;
+ (void)objects;
+ (void)objectsCount;
+}
+
+status_t RpcState::processTransactInternal(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection,
+ std::vector<uint8_t>&& transactionData) {
+ if (transactionData.size() < sizeof(RpcWireTransaction)) {
+ ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
+ sizeof(RpcWireTransaction), transactionData.size());
+ terminate();
+ return BAD_VALUE;
+ }
+ RpcWireTransaction* transaction = reinterpret_cast<RpcWireTransaction*>(transactionData.data());
+
+ // TODO(b/182939933): heap allocation just for lookup in mNodeForAddress,
+ // maybe add an RpcAddress 'view' if the type remains 'heavy'
+ auto addr = RpcAddress::fromRawEmbedded(&transaction->address);
+
+ status_t replyStatus = OK;
+ sp<IBinder> target;
+ if (!addr.isZero()) {
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+
+ auto it = mNodeForAddress.find(addr);
+ if (it == mNodeForAddress.end()) {
+ ALOGE("Unknown binder address %s.", addr.toString().c_str());
+ dump();
+ replyStatus = BAD_VALUE;
+ } else {
+ target = it->second.binder.promote();
+ if (target == nullptr) {
+ // This can happen if the binder is remote in this process, and
+ // another thread has called the last decStrong on this binder.
+ // However, for local binders, it indicates a misbehaving client
+ // (any binder which is being transacted on should be holding a
+ // strong ref count), so in either case, terminating the
+ // connection.
+ ALOGE("While transacting, binder has been deleted at address %s. Terminating!",
+ addr.toString().c_str());
+ terminate();
+ replyStatus = BAD_VALUE;
+ } else if (target->localBinder() == nullptr) {
+ ALOGE("Transactions can only go to local binders, not address %s. Terminating!",
+ addr.toString().c_str());
+ terminate();
+ replyStatus = BAD_VALUE;
+ } else if (transaction->flags & IBinder::FLAG_ONEWAY) {
+ if (transaction->asyncNumber != it->second.asyncNumber) {
+ // we need to process some other asynchronous transaction
+ // first
+ // TODO(b/183140903): limit enqueues/detect overfill for bad client
+ // TODO(b/183140903): detect when an object is deleted when it still has
+ // pending async transactions
+ it->second.asyncTodo.push(BinderNode::AsyncTodo{
+ .data = std::move(transactionData),
+ .asyncNumber = transaction->asyncNumber,
+ });
+ LOG_RPC_DETAIL("Enqueuing %" PRId64 " on %s", transaction->asyncNumber,
+ addr.toString().c_str());
+ return OK;
+ }
+ }
+ }
+ }
+
+ Parcel reply;
+ reply.markForRpc(connection);
+
+ if (replyStatus == OK) {
+ Parcel data;
+ // transaction->data is owned by this function. Parcel borrows this data and
+ // only holds onto it for the duration of this function call. Parcel will be
+ // deleted before the 'transactionData' object.
+ data.ipcSetDataReference(transaction->data,
+ transactionData.size() - offsetof(RpcWireTransaction, data),
+ nullptr /*object*/, 0 /*objectCount*/,
+ do_nothing_to_transact_data);
+ data.markForRpc(connection);
+
+ if (target) {
+ replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
+ } else {
+ LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+ // special case for 'zero' address (special server commands)
+ switch (transaction->code) {
+ case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+ sp<IBinder> root;
+ sp<RpcServer> server = connection->server().promote();
+ if (server) {
+ root = server->getRootObject();
+ } else {
+ ALOGE("Root object requested, but no server attached.");
+ }
+
+ replyStatus = reply.writeStrongBinder(root);
+ break;
+ }
+ default: {
+ replyStatus = UNKNOWN_TRANSACTION;
+ }
+ }
+ }
+ }
+
+ if (transaction->flags & IBinder::FLAG_ONEWAY) {
+ if (replyStatus != OK) {
+ ALOGW("Oneway call failed with error: %d", replyStatus);
+ }
+
+ LOG_RPC_DETAIL("Processed async transaction %" PRId64 " on %s", transaction->asyncNumber,
+ addr.toString().c_str());
+
+ // Check to see if there is another asynchronous transaction to process.
+ // This behavior differs from binder behavior, since in the binder
+ // driver, asynchronous transactions will be processed after existing
+ // pending binder transactions on the queue. The downside of this is
+ // that asynchronous transactions can be drowned out by synchronous
+ // transactions. However, we have no easy way to queue these
+ // transactions after the synchronous transactions we may want to read
+ // from the wire. So, in socket binder here, we have the opposite
+ // downside: asynchronous transactions may drown out synchronous
+ // transactions.
+ {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ auto it = mNodeForAddress.find(addr);
+ // last refcount dropped after this transaction happened
+ if (it == mNodeForAddress.end()) return OK;
+
+ // note - only updated now, instead of later, so that other threads
+ // will queue any later transactions
+
+ // TODO(b/183140903): support > 2**64 async transactions
+ // (we can do this by allowing asyncNumber to wrap, since we
+ // don't expect more than 2**64 simultaneous transactions)
+ it->second.asyncNumber++;
+
+ if (it->second.asyncTodo.size() == 0) return OK;
+ if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
+ LOG_RPC_DETAIL("Found next async transaction %" PRId64 " on %s",
+ it->second.asyncNumber, addr.toString().c_str());
+
+ // justification for const_cast (consider avoiding priority_queue):
+ // - AsyncTodo operator< doesn't depend on 'data' object
+ // - gotta go fast
+ std::vector<uint8_t> data = std::move(
+ const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
+ it->second.asyncTodo.pop();
+ _l.unlock();
+ return processTransactInternal(fd, connection, std::move(data));
+ }
+ }
+ return OK;
+ }
+
+ RpcWireReply rpcReply{
+ .status = replyStatus,
+ };
+
+ std::vector<uint8_t> replyData(sizeof(RpcWireReply) + reply.dataSize());
+ memcpy(replyData.data() + 0, &rpcReply, sizeof(RpcWireReply));
+ memcpy(replyData.data() + sizeof(RpcWireReply), reply.data(), reply.dataSize());
+
+ if (replyData.size() > std::numeric_limits<uint32_t>::max()) {
+ ALOGE("Reply size too big %zu", transactionData.size());
+ terminate();
+ return BAD_VALUE;
+ }
+
+ RpcWireHeader cmdReply{
+ .command = RPC_COMMAND_REPLY,
+ .bodySize = static_cast<uint32_t>(replyData.size()),
+ };
+
+ if (!rpcSend(fd, "reply header", &cmdReply, sizeof(RpcWireHeader))) {
+ return DEAD_OBJECT;
+ }
+ if (!rpcSend(fd, "reply body", replyData.data(), replyData.size())) {
+ return DEAD_OBJECT;
+ }
+ return OK;
+}
+
+status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) {
+ LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
+
+ std::vector<uint8_t> commandData(command.bodySize);
+ if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) {
+ return DEAD_OBJECT;
+ }
+
+ if (command.bodySize < sizeof(RpcWireAddress)) {
+ ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
+ sizeof(RpcWireAddress), command.bodySize);
+ terminate();
+ return BAD_VALUE;
+ }
+ RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
+
+ // TODO(b/182939933): heap allocation just for lookup
+ auto addr = RpcAddress::fromRawEmbedded(address);
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ auto it = mNodeForAddress.find(addr);
+ if (it == mNodeForAddress.end()) {
+ ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
+ dump();
+ return OK;
+ }
+
+ sp<IBinder> target = it->second.binder.promote();
+ if (target == nullptr) {
+ ALOGE("While requesting dec strong, binder has been deleted at address %s. Terminating!",
+ addr.toString().c_str());
+ terminate();
+ return BAD_VALUE;
+ }
+
+ if (it->second.timesSent == 0) {
+ ALOGE("No record of sending binder, but requested decStrong: %s", addr.toString().c_str());
+ return OK;
+ }
+
+ LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %s",
+ addr.toString().c_str());
+
+ sp<IBinder> tempHold;
+
+ it->second.timesSent--;
+ if (it->second.timesSent == 0) {
+ tempHold = it->second.sentRef;
+ it->second.sentRef = nullptr;
+
+ if (it->second.timesRecd == 0) {
+ mNodeForAddress.erase(it);
+ }
+ }
+
+ _l.unlock();
+ tempHold = nullptr; // destructor may make binder calls on this connection
+
+ return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
new file mode 100644
index 0000000..f4f5151
--- /dev/null
+++ b/libs/binder/RpcState.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <binder/RpcConnection.h>
+
+#include <map>
+#include <queue>
+
+namespace android {
+
+struct RpcWireHeader;
+
+/**
+ * Log a lot more information about RPC calls, when debugging issues. Usually,
+ * you would want to enable this in only one process. If repeated issues require
+ * a specific subset of logs to debug, this could be broken up like
+ * IPCThreadState's.
+ */
+#define SHOULD_LOG_RPC_DETAIL false
+
+#if SHOULD_LOG_RPC_DETAIL
+#define LOG_RPC_DETAIL(...) ALOGI(__VA_ARGS__)
+#else
+#define LOG_RPC_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
+#endif
+
+/**
+ * Abstracts away management of ref counts and the wire format from
+ * RpcConnection
+ */
+class RpcState {
+public:
+ RpcState();
+ ~RpcState();
+
+ sp<IBinder> getRootObject(const base::unique_fd& fd, const sp<RpcConnection>& connection);
+
+ [[nodiscard]] status_t transact(const base::unique_fd& fd, const RpcAddress& address,
+ uint32_t code, const Parcel& data,
+ const sp<RpcConnection>& connection, Parcel* reply,
+ uint32_t flags);
+ [[nodiscard]] status_t sendDecStrong(const base::unique_fd& fd, const RpcAddress& address);
+ [[nodiscard]] status_t getAndExecuteCommand(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection);
+
+ /**
+ * Called by Parcel for outgoing binders. This implies one refcount of
+ * ownership to the outgoing binder.
+ */
+ [[nodiscard]] status_t onBinderLeaving(const sp<RpcConnection>& connection,
+ const sp<IBinder>& binder, RpcAddress* outAddress);
+
+ /**
+ * Called by Parcel for incoming binders. This either returns the refcount
+ * to the process, if this process already has one, or it takes ownership of
+ * that refcount
+ */
+ sp<IBinder> onBinderEntering(const sp<RpcConnection>& connection, const RpcAddress& address);
+
+ size_t countBinders();
+ void dump();
+
+private:
+ /**
+ * Called when reading or writing data to a connection fails to clean up
+ * data associated with the connection in order to cleanup binders.
+ * Specifically, we have a strong dependency cycle, since BpBinder is
+ * OBJECT_LIFETIME_WEAK (so that onAttemptIncStrong may return true).
+ *
+ * BpBinder -> RpcConnection -> RpcState
+ * ^-----------------------------/
+ *
+ * In the success case, eventually all refcounts should be propagated over
+ * the connection, though this could also be called to eagerly cleanup
+ * the connection.
+ *
+ * WARNING: RpcState is responsible for calling this when the connection is
+ * no longer recoverable.
+ */
+ void terminate();
+
+ [[nodiscard]] bool rpcSend(const base::unique_fd& fd, const char* what, const void* data,
+ size_t size);
+ [[nodiscard]] bool rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size);
+
+ [[nodiscard]] status_t waitForReply(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection, Parcel* reply);
+ [[nodiscard]] status_t processServerCommand(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection,
+ const RpcWireHeader& command);
+ [[nodiscard]] status_t processTransact(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection,
+ const RpcWireHeader& command);
+ [[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
+ const sp<RpcConnection>& connection,
+ std::vector<uint8_t>&& transactionData);
+ [[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
+ const RpcWireHeader& command);
+
+ struct BinderNode {
+ // Two cases:
+ // A - local binder we are serving
+ // B - remote binder, we are sending transactions to
+ wp<IBinder> binder;
+
+ // if timesSent > 0, this will be equal to binder.promote()
+ sp<IBinder> sentRef;
+
+ // Number of times we've sent this binder out of process, which
+ // translates to an implicit strong count. A client must send RPC binder
+ // socket's dec ref for each time it is sent out of process in order to
+ // deallocate it. Note, a proxy binder we are holding onto might be
+ // sent (this is important when the only remaining refcount of this
+ // binder is the one associated with a transaction sending it back to
+ // its server)
+ size_t timesSent = 0;
+
+ // Number of times we've received this binder, each time corresponds to
+ // a reference we hold over the wire (not a local incStrong/decStrong)
+ size_t timesRecd = 0;
+
+ // transaction ID, for async transactions
+ uint64_t asyncNumber = 0;
+
+ //
+ // CASE A - local binder we are serving
+ //
+
+ // async transaction queue, _only_ for local binder
+ struct AsyncTodo {
+ std::vector<uint8_t> data; // most convenient format, to move it here
+ uint64_t asyncNumber = 0;
+
+ bool operator<(const AsyncTodo& o) const {
+ return asyncNumber > /* !!! */ o.asyncNumber;
+ }
+ };
+ std::priority_queue<AsyncTodo> asyncTodo;
+
+ //
+ // CASE B - remote binder, we are sending transactions to
+ //
+
+ // (no additional data specific to remote binders)
+ };
+
+ std::mutex mNodeMutex;
+ bool mTerminated = false;
+ // binders known by both sides of a connection
+ std::map<RpcAddress, BinderNode> mNodeForAddress;
+};
+
+} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
new file mode 100644
index 0000000..60ec6c9
--- /dev/null
+++ b/libs/binder/RpcWireFormat.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+namespace android {
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wpadded"
+
+enum : uint32_t {
+ /**
+ * follows is RpcWireTransaction, if flags != oneway, reply w/ RPC_COMMAND_REPLY expected
+ */
+ RPC_COMMAND_TRANSACT = 0,
+ /**
+ * follows is RpcWireReply
+ */
+ RPC_COMMAND_REPLY,
+ /**
+ * follows is RpcWireAddress
+ *
+ * note - this in the protocol directly instead of as a 'special
+ * transaction' in order to keep it as lightweight as possible (we don't
+ * want to create a 'Parcel' object for every decref)
+ */
+ RPC_COMMAND_DEC_STRONG,
+};
+
+/**
+ * These commands are used when the address in an RpcWireTransaction is zero'd
+ * out (no address). This allows the transact/reply flow to be used for
+ * additional server commands, without making the protocol for
+ * transactions/replies more complicated.
+ */
+enum : uint32_t {
+ RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
+};
+
+// serialization is like:
+// |RpcWireHeader|struct desginated by 'command'| (over and over again)
+
+struct RpcWireHeader {
+ uint32_t command; // RPC_COMMAND_*
+ uint32_t bodySize;
+
+ uint32_t reserved[2];
+};
+
+struct RpcWireAddress {
+ uint8_t address[32];
+};
+
+struct RpcWireTransaction {
+ RpcWireAddress address;
+ uint32_t code;
+ uint32_t flags;
+
+ uint64_t asyncNumber;
+
+ uint32_t reserved[4];
+
+ uint8_t data[0];
+};
+
+struct RpcWireReply {
+ int32_t status; // transact return
+ uint8_t data[0];
+};
+
+#pragma clang diagnostic pop
+
+} // namespace android
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 339c538..709cf67 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -38,6 +38,30 @@
};
}
+void Stability::forceDowngradeToStability(const sp<IBinder>& binder, Level level) {
+ // Downgrading a remote binder would require also copying the version from
+ // the binder sent here. In practice though, we don't need to downgrade the
+ // stability of a remote binder, since this would as an effect only restrict
+ // what we can do to it.
+ LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder");
+
+ auto stability = Category::currentFromLevel(level);
+ status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::forceDowngradeToLocalStability(const sp<IBinder>& binder) {
+ forceDowngradeToStability(binder, getLocalLevel());
+}
+
+void Stability::forceDowngradeToSystemStability(const sp<IBinder>& binder) {
+ forceDowngradeToStability(binder, Level::SYSTEM);
+}
+
+void Stability::forceDowngradeToVendorStability(const sp<IBinder>& binder) {
+ forceDowngradeToStability(binder, Level::VENDOR);
+}
+
std::string Stability::Category::debugString() {
return levelString(level) + " wire protocol version "
+ std::to_string(version);
@@ -45,13 +69,13 @@
void Stability::markCompilationUnit(IBinder* binder) {
auto stability = Category::currentFromLevel(getLocalLevel());
- status_t result = setRepr(binder, stability.repr(), true /*log*/);
+ status_t result = setRepr(binder, stability.repr(), REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
void Stability::markVintf(IBinder* binder) {
auto stability = Category::currentFromLevel(Level::VINTF);
- status_t result = setRepr(binder, stability.repr(), true /*log*/);
+ status_t result = setRepr(binder, stability.repr(), REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
@@ -62,7 +86,7 @@
void Stability::markVndk(IBinder* binder) {
auto stability = Category::currentFromLevel(Level::VENDOR);
- status_t result = setRepr(binder, stability.repr(), true /*log*/);
+ status_t result = setRepr(binder, stability.repr(), REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
@@ -72,7 +96,7 @@
void Stability::tryMarkCompilationUnit(IBinder* binder) {
auto stability = Category::currentFromLevel(getLocalLevel());
- (void) setRepr(binder, stability.repr(), false /*log*/);
+ (void) setRepr(binder, stability.repr(), REPR_NONE);
}
Stability::Level Stability::getLocalLevel() {
@@ -94,7 +118,10 @@
#endif
}
-status_t Stability::setRepr(IBinder* binder, int32_t representation, bool log) {
+status_t Stability::setRepr(IBinder* binder, int32_t representation, uint32_t flags) {
+ bool log = flags & REPR_LOG;
+ bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE;
+
auto current = getCategory(binder);
auto setting = Category::fromRepr(representation);
@@ -129,7 +156,11 @@
return BAD_TYPE;
}
- if (current.repr() != 0 && current != setting) {
+ if (current == setting) return OK;
+
+ bool hasAlreadyBeenSet = current.repr() != 0;
+ bool isAllowedDowngrade = allowDowngrade && check(current, setting.level);
+ if (hasAlreadyBeenSet && !isAllowedDowngrade) {
if (log) {
ALOGE("Interface being set with %s but it is already marked as %s",
setting.debugString().c_str(),
@@ -138,7 +169,11 @@
return BAD_TYPE;
}
- if (current == setting) return OK;
+ if (isAllowedDowngrade) {
+ ALOGI("Interface set with %s downgraded to %s stability",
+ current.debugString().c_str(),
+ setting.debugString().c_str());
+ }
BBinder* local = binder->localBinder();
if (local != nullptr) {
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 1fbaa13..b58d919 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -25,6 +25,9 @@
"name": "binderLibTest"
},
{
+ "name": "binderRpcTest"
+ },
+ {
"name": "binderStabilityTest"
},
{
@@ -40,6 +43,9 @@
"name": "aidl_integration_test"
},
{
+ "name": "memunreachable_binder_test"
+ },
+ {
"name": "libbinderthreadstateutils_test"
},
{
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 2fabf94..75c4092 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -108,6 +108,11 @@
@utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
/**
+ * If updatable-via-apex, returns the APEX via which this is updated.
+ */
+ @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
+
+ /**
* Request a callback when the number of clients of the service changes.
* Used by LazyServiceRegistrar to dynamically stop services that have no clients.
*/
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 7079544..7e9be41 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -131,8 +131,8 @@
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
- inline IBinder* remote() { return mRemote; }
- inline IBinder* remote() const { return mRemote; }
+ inline IBinder* remote() const { return mRemote; }
+ inline sp<IBinder> remoteStrong() const { return sp<IBinder>::fromExisting(mRemote); }
private:
BpRefBase(const BpRefBase& o);
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 22300ac..ad618f9 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,15 +17,19 @@
#pragma once
#include <binder/IBinder.h>
+#include <binder/RpcAddress.h>
#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include <utils/threads.h>
#include <unordered_map>
+#include <variant>
// ---------------------------------------------------------------------------
namespace android {
+class RpcConnection;
+class RpcState;
namespace internal {
class Stability;
}
@@ -36,7 +40,15 @@
class BpBinder : public IBinder
{
public:
- static BpBinder* create(int32_t handle);
+ static sp<BpBinder> create(int32_t handle);
+ static sp<BpBinder> create(const sp<RpcConnection>& connection, const RpcAddress& address);
+
+ /**
+ * Return value:
+ * true - this is associated with a socket RpcConnection
+ * false - (usual) binder over e.g. /dev/binder
+ */
+ bool isRpcBinder() const;
virtual const String16& getInterfaceDescriptor() const;
virtual bool isBinderAlive() const;
@@ -108,33 +120,57 @@
KeyedVector<const void*, entry_t> mObjects;
};
- class PrivateAccessorForHandle {
+ class PrivateAccessorForId {
private:
- friend BpBinder;
- friend ::android::Parcel;
- friend ::android::ProcessState;
- explicit PrivateAccessorForHandle(const BpBinder* binder) : mBinder(binder) {}
- int32_t handle() const { return mBinder->handle(); }
+ friend class BpBinder;
+ friend class ::android::Parcel;
+ friend class ::android::ProcessState;
+ friend class ::android::RpcState;
+ explicit PrivateAccessorForId(const BpBinder* binder) : mBinder(binder) {}
+
+ // valid if !isRpcBinder
+ int32_t binderHandle() const { return mBinder->binderHandle(); }
+
+ // valid if isRpcBinder
+ const RpcAddress& rpcAddress() const { return mBinder->rpcAddress(); }
+ const sp<RpcConnection>& rpcConnection() const { return mBinder->rpcConnection(); }
+
const BpBinder* mBinder;
};
- const PrivateAccessorForHandle getPrivateAccessorForHandle() const {
- return PrivateAccessorForHandle(this);
+ const PrivateAccessorForId getPrivateAccessorForId() const {
+ return PrivateAccessorForId(this);
}
private:
- friend PrivateAccessorForHandle;
+ friend PrivateAccessorForId;
+ friend class sp<BpBinder>;
- int32_t handle() const;
- BpBinder(int32_t handle,int32_t trackedUid);
+ struct BinderHandle {
+ int32_t handle;
+ };
+ struct SocketHandle {
+ sp<RpcConnection> connection;
+ RpcAddress address;
+ };
+ using Handle = std::variant<BinderHandle, SocketHandle>;
+
+ int32_t binderHandle() const;
+ const RpcAddress& rpcAddress() const;
+ const sp<RpcConnection>& rpcConnection() const;
+
+ explicit BpBinder(Handle&& handle);
+ BpBinder(BinderHandle&& handle, int32_t trackedUid);
+ explicit BpBinder(SocketHandle&& handle);
+
virtual ~BpBinder();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
friend ::android::internal::Stability;
- int32_t mStability;
- const int32_t mHandle;
+ int32_t mStability;
+ Handle mHandle;
struct Obituary {
wp<DeathRecipient> recipient;
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index f4a21dd..f35e2db 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -143,11 +143,10 @@
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != nullptr) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
+ intr = ::android::sp<I##INTERFACE>::cast( \
+ obj->queryLocalInterface(I##INTERFACE::descriptor)); \
if (intr == nullptr) { \
- intr = new Bp##INTERFACE(obj); \
+ intr = ::android::sp<Bp##INTERFACE>::make(obj); \
} \
} \
return intr; \
@@ -186,7 +185,7 @@
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
const String16& _descriptor)
{
- if (_descriptor == INTERFACE::descriptor) return this;
+ if (_descriptor == INTERFACE::descriptor) return sp<IInterface>::fromExisting(this);
return nullptr;
}
diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
deleted file mode 100644
index f92d557..0000000
--- a/libs/binder/include/binder/IMediaResourceMonitor.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 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
-
-#ifndef __ANDROID_VNDK__
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IMediaResourceMonitor : public IInterface {
-public:
- DECLARE_META_INTERFACE(MediaResourceMonitor)
-
- // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX.
- enum {
- TYPE_VIDEO_CODEC = 0,
- TYPE_AUDIO_CODEC = 1,
- };
-
- virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
-
- enum {
- NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION,
- };
-};
-
-// ----------------------------------------------------------------------
-
-class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> {
-public:
- // NOLINTNEXTLINE(google-default-arguments)
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-} // namespace android
-
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 5f0d056..3dbe2c4 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -20,6 +20,8 @@
#include <utils/Vector.h>
#include <utils/String16.h>
+#include <optional>
+
namespace android {
// ----------------------------------------------------------------------
@@ -99,6 +101,12 @@
* Get all instances of a service as declared in the VINTF manifest
*/
virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0;
+
+ /**
+ * If this instance is updatable via an APEX, returns the APEX with which
+ * this can be updated.
+ */
+ virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
deleted file mode 100644
index a8faa3f..0000000
--- a/libs/binder/include/binder/IpPrefix.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 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
-
-#ifndef __ANDROID_VNDK__
-
-#include <netinet/in.h>
-
-#include <binder/Parcelable.h>
-#include <utils/String16.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-
-namespace net {
-
-/*
- * C++ implementation of the Java class android.net.IpPrefix
- */
-class IpPrefix : public Parcelable {
-public:
- IpPrefix() = default;
- virtual ~IpPrefix() = default;
- IpPrefix(const IpPrefix& prefix) = default;
-
- IpPrefix(const struct in6_addr& addr, int32_t plen):
- mUnion(addr), mPrefixLength(plen), mIsIpv6(true) { }
-
- IpPrefix(const struct in_addr& addr, int32_t plen):
- mUnion(addr), mPrefixLength(plen), mIsIpv6(false) { }
-
- bool getAddressAsIn6Addr(struct in6_addr* addr) const;
- bool getAddressAsInAddr(struct in_addr* addr) const;
-
- const struct in6_addr& getAddressAsIn6Addr() const;
- const struct in_addr& getAddressAsInAddr() const;
-
- bool isIpv6() const;
- bool isIpv4() const;
-
- int32_t getPrefixLength() const;
-
- void setAddress(const struct in6_addr& addr);
- void setAddress(const struct in_addr& addr);
-
- void setPrefixLength(int32_t prefix);
-
- friend bool operator==(const IpPrefix& lhs, const IpPrefix& rhs);
-
- friend bool operator!=(const IpPrefix& lhs, const IpPrefix& rhs) {
- return !(lhs == rhs);
- }
-
-public:
- // Overrides
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
-private:
- union InternalUnion {
- InternalUnion() = default;
- explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { }
- explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { }
- struct in6_addr mIn6Addr;
- struct in_addr mInAddr;
- } mUnion;
- int32_t mPrefixLength;
- bool mIsIpv6;
-};
-
-} // namespace net
-
-} // namespace android
-
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 7b298f5..9578372 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -50,11 +50,14 @@
class IBinder;
class IPCThreadState;
class ProcessState;
+class RpcConnection;
class String8;
class TextOutput;
class Parcel {
friend class IPCThreadState;
+ friend class RpcState;
+
public:
class ReadableBlob;
class WritableBlob;
@@ -92,7 +95,21 @@
// In order to verify this, heap dumps should be used.
void markSensitive() const;
- // Writes the RPC header.
+ // For a 'data' Parcel, this should mark the Parcel as being prepared for a
+ // transaction on this specific binder object. Based on this, the format of
+ // the wire binder protocol may change (data is written differently when it
+ // is for an RPC transaction).
+ void markForBinder(const sp<IBinder>& binder);
+
+ // Whenever possible, markForBinder should be preferred. This method is
+ // called automatically on reply Parcels for RPC transactions.
+ void markForRpc(const sp<RpcConnection>& connection);
+
+ // Whether this Parcel is written for RPC transactions (after calls to
+ // markForBinder or markForRpc).
+ bool isForRpc() const;
+
+ // Writes the IPC/RPC header.
status_t writeInterfaceToken(const String16& interface);
status_t writeInterfaceToken(const char16_t* str, size_t len);
@@ -1106,6 +1123,7 @@
mutable bool mObjectsSorted;
mutable bool mRequestHeaderPresent;
+
mutable size_t mWorkSourceRequestHeaderPosition;
mutable bool mFdsKnown;
@@ -1118,8 +1136,7 @@
release_func mOwner;
- // TODO(167966510): reserved for binder/version/stability
- void* mReserved = reinterpret_cast<void*>(0xAAAAAAAA);
+ sp<RpcConnection> mConnection;
class Blob {
public:
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 2405ab6..b9db5d7 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -58,6 +58,7 @@
void spawnPooledThread(bool isMain);
status_t setThreadPoolMaxThreadCount(size_t maxThreads);
+ status_t enableOnewaySpamDetection(bool enable);
void giveThreadPoolName();
String8 getDriverName();
@@ -88,7 +89,8 @@
static sp<ProcessState> init(const char *defaultDriver, bool requireDefault);
friend class IPCThreadState;
-
+ friend class sp<ProcessState>;
+
explicit ProcessState(const char* driver);
~ProcessState();
@@ -124,7 +126,6 @@
Vector<handle_entry>mHandleToObject;
- String8 mRootDir;
bool mThreadPoolStarted;
volatile int32_t mThreadPoolSeq;
diff --git a/libs/binder/include/binder/RpcAddress.h b/libs/binder/include/binder/RpcAddress.h
new file mode 100644
index 0000000..5a3f3a6
--- /dev/null
+++ b/libs/binder/include/binder/RpcAddress.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+
+#include <utils/Errors.h>
+
+// WARNING: This is a feature which is still in development, and it is subject
+// to radical change. Any production use of this may subject your code to any
+// number of problems.
+
+namespace android {
+
+class Parcel;
+struct RpcWireAddress;
+
+/**
+ * This class represents an identifier of a binder object.
+ *
+ * The purpose of this class it to hide the ABI of an RpcWireAddress, and
+ * potentially allow us to change the size of it in the future (RpcWireAddress
+ * is PIMPL, essentially - although the type that is used here is not exposed).
+ */
+class RpcAddress {
+public:
+ /**
+ * The zero address is used for special RPC transactions, but it might also
+ * be used in conjunction with readFromParcel.
+ */
+ static RpcAddress zero();
+
+ bool isZero() const;
+
+ /**
+ * Create a new address which is unique
+ */
+ static RpcAddress unique();
+
+ /**
+ * Creates a new address as a copy of an embedded object.
+ */
+ static RpcAddress fromRawEmbedded(const RpcWireAddress* raw);
+ const RpcWireAddress& viewRawEmbedded() const;
+
+ bool operator<(const RpcAddress& rhs) const;
+ std::string toString() const;
+
+ status_t writeToParcel(Parcel* parcel) const;
+ status_t readFromParcel(const Parcel& parcel);
+
+ ~RpcAddress();
+
+private:
+ RpcAddress();
+
+ std::shared_ptr<RpcWireAddress> mRawAddr;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
new file mode 100644
index 0000000..2395e78
--- /dev/null
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/RpcAddress.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <optional>
+#include <vector>
+
+// WARNING: This is a feature which is still in development, and it is subject
+// to radical change. Any production use of this may subject your code to any
+// number of problems.
+
+namespace android {
+
+class Parcel;
+class RpcServer;
+class RpcState;
+
+/**
+ * This represents a multi-threaded/multi-socket connection between a client
+ * and a server.
+ */
+class RpcConnection final : public virtual RefBase {
+public:
+ static sp<RpcConnection> make();
+
+ /**
+ * This represents a connection for responses, e.g.:
+ *
+ * process A serves binder a
+ * process B opens a connection to process A
+ * process B makes binder b and sends it to A
+ * A uses this 'back connection' to send things back to B
+ *
+ * This should be called once, and then a call should be made to join per
+ * connection thread.
+ */
+ [[nodiscard]] bool setupUnixDomainServer(const char* path);
+
+ /**
+ * This should be called once per thread, matching 'join' in the remote
+ * process.
+ */
+ [[nodiscard]] bool addUnixDomainClient(const char* path);
+
+#ifdef __BIONIC__
+ /**
+ * Creates an RPC server at the current port.
+ */
+ [[nodiscard]] bool setupVsockServer(unsigned int port);
+
+ /**
+ * Connects to an RPC server at the CVD & port.
+ */
+ [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
+#endif // __BIONIC__
+
+ /**
+ * Creates an RPC server at the current port.
+ */
+ [[nodiscard]] bool setupInetServer(unsigned int port);
+
+ /**
+ * Connects to an RPC server at the given address and port.
+ */
+ [[nodiscard]] bool addInetClient(const char* addr, unsigned int port);
+
+ /**
+ * For debugging!
+ *
+ * Sets up an empty socket. All queries to this socket which require a
+ * response will never be satisfied. All data sent here will be
+ * unceremoniously cast down the bottomless pit, /dev/null.
+ */
+ [[nodiscard]] bool addNullDebuggingClient();
+
+ /**
+ * Query the other side of the connection for the root object hosted by that
+ * process's RpcServer (if one exists)
+ */
+ sp<IBinder> getRootObject();
+
+ [[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
+
+ /**
+ * Adds a server thread accepting connections. Must be called after
+ * setup*Server.
+ */
+ void join();
+
+ ~RpcConnection();
+
+ void setForServer(const wp<RpcServer>& server);
+ wp<RpcServer> server();
+
+ // internal only
+ const std::unique_ptr<RpcState>& state() { return mState; }
+
+ class SocketAddress {
+ public:
+ virtual ~SocketAddress();
+ virtual std::string toString() const = 0;
+ virtual const sockaddr* addr() const = 0;
+ virtual size_t addrSize() const = 0;
+ };
+
+private:
+ friend sp<RpcConnection>;
+ RpcConnection();
+
+ struct ConnectionSocket : public RefBase {
+ base::unique_fd fd;
+
+ // whether this or another thread is currently using this fd to make
+ // or receive transactions.
+ std::optional<pid_t> exclusiveTid;
+ };
+
+ bool setupSocketServer(const SocketAddress& address);
+ bool addSocketClient(const SocketAddress& address);
+ void addClient(base::unique_fd&& fd);
+ sp<ConnectionSocket> assignServerToThisThread(base::unique_fd&& fd);
+ bool removeServerSocket(const sp<ConnectionSocket>& socket);
+
+ enum class SocketUse {
+ CLIENT,
+ CLIENT_ASYNC,
+ CLIENT_REFCOUNT,
+ };
+
+ // RAII object for connection socket
+ class ExclusiveSocket {
+ public:
+ explicit ExclusiveSocket(const sp<RpcConnection>& connection, SocketUse use);
+ ~ExclusiveSocket();
+ const base::unique_fd& fd() { return mSocket->fd; }
+
+ private:
+ static void findSocket(pid_t tid, sp<ConnectionSocket>* exclusive,
+ sp<ConnectionSocket>* available,
+ std::vector<sp<ConnectionSocket>>& sockets, size_t socketsIndexHint);
+
+ sp<RpcConnection> mConnection; // avoid deallocation
+ sp<ConnectionSocket> mSocket;
+
+ // whether this is being used for a nested transaction (being on the same
+ // thread guarantees we won't write in the middle of a message, the way
+ // the wire protocol is constructed guarantees this is safe).
+ bool mReentrant = false;
+ };
+
+ // On the other side of a connection, for each of mClients here, there should
+ // be one of mServers on the other side (and vice versa).
+ //
+ // For the simplest connection, a single server with one client, you would
+ // have:
+ // - the server has a single 'mServers' and a thread listening on this
+ // - the client has a single 'mClients' and makes calls to this
+ // - here, when the client makes a call, the server can call back into it
+ // (nested calls), but outside of this, the client will only ever read
+ // calls from the server when it makes a call itself.
+ //
+ // For a more complicated case, the client might itself open up a thread to
+ // serve calls to the server at all times (e.g. if it hosts a callback)
+
+ wp<RpcServer> mForServer; // maybe null, for client connections
+
+ std::unique_ptr<RpcState> mState;
+
+ base::unique_fd mServer; // socket we are accepting connections on
+
+ std::mutex mSocketMutex; // for all below
+ std::condition_variable mSocketCv; // for mWaitingThreads
+ size_t mWaitingThreads = 0;
+ size_t mClientsOffset = 0; // hint index into clients, ++ when sending an async transaction
+ std::vector<sp<ConnectionSocket>> mClients;
+ std::vector<sp<ConnectionSocket>> mServers;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
new file mode 100644
index 0000000..d29b651
--- /dev/null
+++ b/libs/binder/include/binder/RpcServer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/RpcConnection.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// WARNING: This is a feature which is still in development, and it is subject
+// to radical change. Any production use of this may subject your code to any
+// number of problems.
+
+namespace android {
+
+/**
+ * This represents a server of an interface, which may be connected to by any
+ * number of clients over sockets.
+ *
+ * This object is not (currently) thread safe. All calls to it are expected to
+ * happen at process startup.
+ */
+class RpcServer final : public virtual RefBase {
+public:
+ static sp<RpcServer> make();
+
+ void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+ /**
+ * Setup a static connection, when the number of clients are known.
+ *
+ * Each call to this function corresponds to a different client, and clients
+ * each have their own threadpools.
+ *
+ * TODO(b/167966510): support dynamic creation of connections/threads
+ */
+ sp<RpcConnection> addClientConnection();
+
+ /**
+ * Allowing a server to explicitly drop clients would be easy to add here,
+ * but it is not currently implemented, since users of this functionality
+ * could not use similar functionality if they are running under real
+ * binder.
+ */
+ // void drop(const sp<RpcConnection>& connection);
+
+ /**
+ * The root object can be retrieved by any client, without any
+ * authentication.
+ */
+ void setRootObject(const sp<IBinder>& binder);
+
+ /**
+ * Root object set with setRootObject
+ */
+ sp<IBinder> getRootObject();
+
+ ~RpcServer();
+
+private:
+ friend sp<RpcServer>;
+ RpcServer();
+
+ bool mAgreedExperimental = false;
+
+ sp<IBinder> mRootObject;
+
+ std::vector<sp<RpcConnection>> mConnections; // per-client
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 12272ba..f4bfac8 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -49,10 +49,42 @@
// that it knows how to process. The summary of stability of a binder is
// represented by a Stability::Category object.
-// WARNING: These APIs are only ever expected to be called by auto-generated code.
-// Instead of calling them, you should set the stability of a .aidl interface
class Stability final {
public:
+ // Given a binder interface at a certain stability, there may be some
+ // requirements associated with that higher stability level. For instance, a
+ // VINTF stability binder is required to be in the VINTF manifest. This API
+ // can be called to use that same interface within the local partition.
+ static void forceDowngradeToLocalStability(const sp<IBinder>& binder);
+
+ // WARNING: Below APIs are only ever expected to be called by auto-generated code.
+ // Instead of calling them, you should set the stability of a .aidl interface
+
+ // WARNING: The only client of
+ // - forceDowngradeToSystemStability() and;
+ // - korceDowngradeToVendorStability()
+ // should be AIBinder_forceDowngradeToLocalStability().
+ //
+ // getLocalLevel() in libbinder returns Level::SYSTEM when called
+ // from libbinder_ndk (even on vendor partition). So we explicitly provide
+ // these methods for use by the NDK API:
+ // AIBinder_forceDowngradeToLocalStability().
+ //
+ // This allows correctly downgrading the binder's stability to either system/vendor,
+ // depending on the partition.
+
+ // Given a binder interface at a certain stability, there may be some
+ // requirements associated with that higher stability level. For instance, a
+ // VINTF stability binder is required to be in the VINTF manifest. This API
+ // can be called to use that same interface within the vendor partition.
+ static void forceDowngradeToVendorStability(const sp<IBinder>& binder);
+
+ // Given a binder interface at a certain stability, there may be some
+ // requirements associated with that higher stability level. For instance, a
+ // VINTF stability binder is required to be in the VINTF manifest. This API
+ // can be called to use that same interface within the system partition.
+ static void forceDowngradeToSystemStability(const sp<IBinder>& binder);
+
// WARNING: This is only ever expected to be called by auto-generated code. You likely want to
// change or modify the stability class of the interface you are using.
// This must be called as soon as the binder in question is constructed. No thread safety
@@ -139,9 +171,17 @@
// returns the stability according to how this was built
static Level getLocalLevel();
+ // Downgrades binder stability to the specified level.
+ static void forceDowngradeToStability(const sp<IBinder>& binder, Level level);
+
+ enum {
+ REPR_NONE = 0,
+ REPR_LOG = 1,
+ REPR_ALLOW_DOWNGRADE = 2,
+ };
// applies stability to binder if stability level is known
__attribute__((warn_unused_result))
- static status_t setRepr(IBinder* binder, int32_t representation, bool log);
+ static status_t setRepr(IBinder* binder, int32_t representation, uint32_t flags);
// get stability information as encoded on the wire
static Category getCategory(IBinder* binder);
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index c30ae01..aaafa36 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -91,6 +91,9 @@
static Status fromExceptionCode(int32_t exceptionCode,
const char* message);
+ // warning: this is still considered an error if it is constructed with a
+ // zero value error code. Please use Status::ok() instead and avoid zero
+ // error codes
static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode);
static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
const String8& message);
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 1579199..151235c 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -32,10 +32,6 @@
#include <sys/ioctl.h>
#include <linux/android/binder.h>
-#ifdef __cplusplus
-namespace android {
-#endif
-
#ifndef BR_FROZEN_REPLY
// Temporary definition of BR_FROZEN_REPLY. For production
// this will come from UAPI binder.h
@@ -88,8 +84,18 @@
};
#endif //BINDER_GET_FROZEN_INFO
-#ifdef __cplusplus
-} // namespace android
-#endif
+#ifndef BR_ONEWAY_SPAM_SUSPECT
+// Temporary definition of BR_ONEWAY_SPAM_SUSPECT. For production
+// this will come from UAPI binder.h
+#define BR_ONEWAY_SPAM_SUSPECT _IO('r', 19)
+#endif //BR_ONEWAY_SPAM_SUSPECT
+
+#ifndef BINDER_ENABLE_ONEWAY_SPAM_DETECTION
+/*
+ * Temporary definitions for oneway spam detection support. For the final version
+ * these will be defined in the UAPI binder.h file from upstream kernel.
+ */
+#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
+#endif //BINDER_ENABLE_ONEWAY_SPAM_DETECTION
#endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
similarity index 100%
rename from libs/binder/include/binder/ActivityManager.h
rename to libs/binder/include_activitymanager/binder/ActivityManager.h
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include_activitymanager/binder/IActivityManager.h
similarity index 99%
rename from libs/binder/include/binder/IActivityManager.h
rename to libs/binder/include_activitymanager/binder/IActivityManager.h
index fde56a0..e3b5e43 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/IActivityManager.h
@@ -18,8 +18,8 @@
#ifndef __ANDROID_VNDK__
-#include <binder/IInterface.h>
#include <binder/IUidObserver.h>
+#include <binder/IInterface.h>
namespace android {
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include_activitymanager/binder/IUidObserver.h
similarity index 100%
rename from libs/binder/include/binder/IUidObserver.h
rename to libs/binder/include_activitymanager/binder/IUidObserver.h
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include_batterystats/batterystats/IBatteryStats.h
similarity index 100%
rename from libs/binder/include/binder/IBatteryStats.h
rename to libs/binder/include_batterystats/batterystats/IBatteryStats.h
diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include_processinfo/processinfo/IProcessInfoService.h
similarity index 100%
rename from libs/binder/include/binder/IProcessInfoService.h
rename to libs/binder/include_processinfo/processinfo/IProcessInfoService.h
diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include_processinfo/processinfo/ProcessInfoService.h
similarity index 98%
rename from libs/binder/include/binder/ProcessInfoService.h
rename to libs/binder/include_processinfo/processinfo/ProcessInfoService.h
index 6b3b5ce..978856d 100644
--- a/libs/binder/include/binder/ProcessInfoService.h
+++ b/libs/binder/include_processinfo/processinfo/ProcessInfoService.h
@@ -18,7 +18,7 @@
#ifndef __ANDROID_VNDK__
-#include <binder/IProcessInfoService.h>
+#include <processinfo/IProcessInfoService.h>
#include <utils/Errors.h>
#include <utils/Singleton.h>
#include <sys/types.h>
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 0f59de4..883403a 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -363,7 +363,8 @@
}
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
- CHECK(who == mWho);
+ CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get()
+ << " (" << mWho.get_refs() << ")";
mOnDied(mCookie);
@@ -598,6 +599,8 @@
}
*in = new AParcel(binder);
+ (*in)->get()->markForBinder(binder->getBinder());
+
status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
binder_status_t ret = PruneStatusT(status);
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 05eb64b..6c44726 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -82,7 +82,10 @@
*/
template <class T, class... Args>
static std::shared_ptr<T> make(Args&&... args) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
T* t = new T(std::forward<Args>(args)...);
+#pragma clang diagnostic pop
// warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc]
return t->template ref<T>(); // NOLINT(clang-analyzer-unix.Malloc)
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index a44c261..9e2050b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -36,11 +36,9 @@
__BEGIN_DECLS
-#ifndef __ANDROID_API__
-#error Android builds must be compiled against a specific API. If this is an \
- android platform host build, you must use libbinder_ndk_host_user.
-#endif
-
+/**
+ * Flags for AIBinder_transact.
+ */
typedef uint32_t binder_flags_t;
enum {
/**
@@ -52,7 +50,10 @@
FLAG_ONEWAY = 0x01,
};
-// Also see IBinder.h in libbinder
+/**
+ * Codes for AIBinder_transact. This defines the range of codes available for
+ * usage. Other codes are used or reserved by the Android system.
+ */
typedef uint32_t transaction_code_t;
enum {
/**
@@ -172,7 +173,7 @@
* Available since API level 29.
*
* \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
- * sanity checks on transactions.
+ * validity checks on transactions. This should be utf-8.
* \param onCreate see AIBinder_Class_onCreate.
* \param onDestroy see AIBinder_Class_onDestroy.
* \param onTransact see AIBinder_Class_onTransact.
@@ -207,7 +208,8 @@
*
* Available since API level 29.
*
- * \param dump function to call when an instance of this binder class is being dumped.
+ * \param clazz class which should use this dump function
+ * \param onDump function to call when an instance of this binder class is being dumped.
*/
void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
@@ -643,7 +645,9 @@
*
* \return the class descriptor string. This pointer will never be null; a
* descriptor is required to define a class. The pointer is owned by the class
- * and will remain valid as long as the class does.
+ * and will remain valid as long as the class does. For a local class, this will
+ * be the same value (not necessarily pointer equal) as is passed into
+ * AIBinder_Class_define. Format is utf-8.
*/
const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUCED_IN(31);
@@ -667,7 +671,7 @@
*
* \return whether "lhs < rhs" is true
*/
-bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs);
+bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs) __INTRODUCED_IN(31);
/**
* Clone an AIBinder_Weak. Useful because even if a weak binder promotes to a
@@ -681,7 +685,7 @@
* \return clone of the input parameter. This must be deleted with
* AIBinder_Weak_delete. Null if weak input parameter is also null.
*/
-AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak);
+AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak) __INTRODUCED_IN(31);
/**
* Whether AIBinder_Weak is less than another.
@@ -716,7 +720,7 @@
*
* \return whether "lhs < rhs" is true
*/
-bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs);
+bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs) __INTRODUCED_IN(31);
__END_DECLS
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 05b25e7..6f1fdfc 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -32,6 +32,16 @@
__BEGIN_DECLS
+#ifndef __ANDROID_API__
+#error Android builds must be compiled against a specific API. If this is an \
+ android platform host build, you must use libbinder_ndk_host_user.
+#endif
+
+/**
+ * Low-level status types for use in binder. This is the least preferable way to
+ * return an error for binder services (where binder_exception_t should be used,
+ * particularly EX_SERVICE_SPECIFIC).
+ */
enum {
STATUS_OK = 0,
@@ -62,6 +72,10 @@
*/
typedef int32_t binder_status_t;
+/**
+ * Top level exceptions types for Android binder errors, mapping to Java
+ * exceptions. Also see Parcel.java.
+ */
enum {
EX_NONE = 0,
EX_SECURITY = -1,
@@ -170,11 +184,12 @@
/**
* New status with binder_status_t. This is typically for low level failures when a binder_status_t
* is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
- * an AStatus instance.
+ * an AStatus instance. This is the least preferable way to return errors.
+ * Prefer exceptions (particularly service-specific errors) when possible.
*
* Available since API level 29.
*
- * \param a low-level error to associate with this status object.
+ * \param status a low-level error to associate with this status object.
*
* \return a newly constructed status object that the caller owns.
*/
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 5df0012..a90b4aa 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -26,6 +26,9 @@
* This registers the service with the default service manager under this instance name. This does
* not take ownership of binder.
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param binder object to register globally with the service manager.
* \param instance identifier of the service. This will be used to lookup the service.
*
@@ -39,6 +42,9 @@
* service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
* function is responsible for calling AIBinder_decStrong).
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
@@ -48,6 +54,9 @@
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
@@ -78,6 +87,9 @@
* This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param instance identifier of the service used to lookup the service.
*
* \return service if registered, null if not.
@@ -112,6 +124,15 @@
__INTRODUCED_IN(31);
/**
+ * Check if a service is updatable via an APEX module.
+ *
+ * \param instance identifier of the service
+ *
+ * \return whether the interface is updatable via APEX
+ */
+bool AServiceManager_isUpdatableViaApex(const char* instance) __INTRODUCED_IN(31);
+
+/**
* Prevent lazy services without client from shutting down their process
*
* \param persist 'true' if the process should not exit.
diff --git a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
index d54c1a1..6372449 100644
--- a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
@@ -20,9 +20,7 @@
__BEGIN_DECLS
-#if defined(__ANDROID_APEX__) || defined(__ANDROID_VNDK__)
-#error this is only for platform code
-#endif
+#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
/**
* Gets whether or not FDs are allowed by this AParcel
@@ -33,6 +31,9 @@
*/
bool AParcel_getAllowFds(const AParcel*);
+#endif
+
+#if !defined(__ANDROID_APEX__)
/**
* Data written to the parcel will be zero'd before being deleted or realloced.
*
@@ -43,5 +44,6 @@
* \param parcel The parcel to clear associated data from.
*/
void AParcel_markSensitive(const AParcel* parcel);
+#endif
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index f5e8bf6..f113ba8 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,7 +30,7 @@
FLAG_PRIVATE_VENDOR = 0x10000000,
};
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_VENDOR__)
enum {
FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
@@ -45,7 +45,19 @@
AIBinder_markVendorStability(binder);
}
-#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+/**
+ * Given a binder interface at a certain stability, there may be some
+ * requirements associated with that higher stability level. For instance, a
+ * VINTF stability binder is required to be in the VINTF manifest. This API
+ * can be called to use that same interface within the vendor partition.
+ */
+void AIBinder_forceDowngradeToVendorStability(AIBinder* binder);
+
+static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) {
+ AIBinder_forceDowngradeToVendorStability(binder);
+}
+
+#else // defined(__ANDROID_VENDOR__)
enum {
FLAG_PRIVATE_LOCAL = 0,
@@ -62,9 +74,27 @@
AIBinder_markSystemStability(binder);
}
-#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+/**
+ * Given a binder interface at a certain stability, there may be some
+ * requirements associated with that higher stability level. For instance, a
+ * VINTF stability binder is required to be in the VINTF manifest. This API
+ * can be called to use that same interface within the system partition.
+ */
+void AIBinder_forceDowngradeToSystemStability(AIBinder* binder);
+
+static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) {
+ AIBinder_forceDowngradeToSystemStability(binder);
+}
+
+#endif // defined(__ANDROID_VENDOR__)
/**
+ * WARNING: this is not expected to be used manually. When the build system has
+ * versioned checks in place for an interface that prevent it being changed year
+ * over year (specifically like those for @VintfStability stable AIDL
+ * interfaces), this could be called. Calling this without this or equivalent
+ * infrastructure will lead to de facto frozen APIs or GSI test failures.
+ *
* This interface has system<->vendor stability
*/
void AIBinder_markVintfStability(AIBinder* binder);
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 8d08275..7d4b82e 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -117,14 +117,19 @@
ABinderProcess_setupPolling; # apex
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
- AServiceManager_isDeclared; # apex llndk
+ AParcel_markSensitive; # llndk
AServiceManager_forEachDeclaredInstance; # apex llndk
- AServiceManager_registerLazyService; # llndk
- AServiceManager_waitForService; # apex llndk
AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_isDeclared; # apex llndk
+ AServiceManager_isUpdatableViaApex; # apex
+ AServiceManager_reRegister; # llndk
+ AServiceManager_registerLazyService; # llndk
AServiceManager_setActiveServicesCallback; # llndk
AServiceManager_tryUnregister; # llndk
- AServiceManager_reRegister; # llndk
+ AServiceManager_waitForService; # apex llndk
+
+ AIBinder_forceDowngradeToSystemStability; # apex
+ AIBinder_forceDowngradeToVendorStability; # llndk
AIBinder_Class_getDescriptor;
AIBinder_Weak_clone;
@@ -139,7 +144,6 @@
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
- AParcel_markSensitive;
extern "C++" {
AIBinder_fromPlatformBinder*;
AIBinder_toPlatformBinder*;
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
index 6b7295e..b4f6358 100644
--- a/libs/binder/ndk/parcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -27,9 +27,8 @@
const ::android::Parcel* get() const { return mParcel; }
::android::Parcel* get() { return mParcel; }
- explicit AParcel(const AIBinder* binder)
- : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
- AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
+ explicit AParcel(AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
+ AParcel(AIBinder* binder, ::android::Parcel* parcel, bool owns)
: mBinder(binder), mParcel(parcel), mOwns(owns) {}
~AParcel() {
@@ -38,7 +37,7 @@
}
}
- static const AParcel readOnly(const AIBinder* binder, const ::android::Parcel* parcel) {
+ static const AParcel readOnly(AIBinder* binder, const ::android::Parcel* parcel) {
return AParcel(binder, const_cast<::android::Parcel*>(parcel), false);
}
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 1ccd0d2..7649a26 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -105,6 +105,14 @@
callback(String8(instance).c_str(), context);
}
}
+bool AServiceManager_isUpdatableViaApex(const char* instance) {
+ if (instance == nullptr) {
+ return false;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ return sm->updatableViaApex(String16(instance)) != std::nullopt;
+}
void AServiceManager_forceLazyServicesPersist(bool persist) {
auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
serviceRegistrar.forcePersist(persist);
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
index a5b3ece..7eafb9c 100644
--- a/libs/binder/ndk/stability.cpp
+++ b/libs/binder/ndk/stability.cpp
@@ -31,7 +31,7 @@
#error libbinder_ndk should only be built in a system context
#endif
-// explicit extern because symbol is only declared in header when __ANDROID_VNDK__
+// explicit extern because symbol is only declared in header when __ANDROID_VENDOR__
extern "C" void AIBinder_markVendorStability(AIBinder* binder) {
Stability::markVndk(binder->getBinder().get());
}
@@ -43,3 +43,12 @@
void AIBinder_markVintfStability(AIBinder* binder) {
Stability::markVintf(binder->getBinder().get());
}
+
+// explicit extern because symbol is only declared in header when __ANDROID_VENDOR__
+extern "C" void AIBinder_forceDowngradeToVendorStability(AIBinder* binder) {
+ Stability::forceDowngradeToVendorStability(binder->getBinder());
+}
+
+void AIBinder_forceDowngradeToSystemStability(AIBinder* binder) {
+ Stability::forceDowngradeToSystemStability(binder->getBinder());
+}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 496a915..1c43948 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -280,6 +280,11 @@
EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
}
+TEST(NdkBinder, IsUpdatable) {
+ bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default");
+ EXPECT_EQ(isUpdatable, false);
+}
+
// This is too slow
TEST(NdkBinder, CheckLazyServiceShutDown) {
ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index e12a429..57c9013 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -65,15 +65,15 @@
// rustified
"--constified-enum", "android::c_interface::consts::.*",
- "--whitelist-type", "android::c_interface::.*",
- "--whitelist-type", "AStatus",
- "--whitelist-type", "AIBinder_Class",
- "--whitelist-type", "AIBinder",
- "--whitelist-type", "AIBinder_Weak",
- "--whitelist-type", "AIBinder_DeathRecipient",
- "--whitelist-type", "AParcel",
- "--whitelist-type", "binder_status_t",
- "--whitelist-function", ".*",
+ "--allowlist-type", "android::c_interface::.*",
+ "--allowlist-type", "AStatus",
+ "--allowlist-type", "AIBinder_Class",
+ "--allowlist-type", "AIBinder",
+ "--allowlist-type", "AIBinder_Weak",
+ "--allowlist-type", "AIBinder_DeathRecipient",
+ "--allowlist-type", "AParcel",
+ "--allowlist-type", "binder_status_t",
+ "--allowlist-function", ".*",
],
shared_libs: [
"libbinder_ndk",
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index d53a88f..695a83e 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -33,13 +33,13 @@
/// Binder action to perform.
///
-/// This must be a number between [`IBinder::FIRST_CALL_TRANSACTION`] and
-/// [`IBinder::LAST_CALL_TRANSACTION`].
+/// This must be a number between [`FIRST_CALL_TRANSACTION`] and
+/// [`LAST_CALL_TRANSACTION`].
pub type TransactionCode = u32;
/// Additional operation flags.
///
-/// `IBinder::FLAG_*` values.
+/// `FLAG_*` values.
pub type TransactionFlags = u32;
/// Super-trait for Binder interfaces.
@@ -56,6 +56,26 @@
}
}
+/// Interface stability promise
+///
+/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
+/// makes no stability guarantees ([`Local`]). [`Local`] is
+/// currently the default stability.
+pub enum Stability {
+ /// Default stability, visible to other modules in the same compilation
+ /// context (e.g. modules on system.img)
+ Local,
+
+ /// A Vendor Interface Object, which promises to be stable
+ Vintf,
+}
+
+impl Default for Stability {
+ fn default() -> Self {
+ Stability::Local
+ }
+}
+
/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
@@ -85,20 +105,24 @@
fn get_class() -> InterfaceClass;
}
-/// Interface of binder local or remote objects.
+/// First transaction code available for user commands (inclusive)
+pub const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION;
+/// Last transaction code available for user commands (inclusive)
+pub const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION;
+
+/// Corresponds to TF_ONE_WAY -- an asynchronous call.
+pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
+/// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
+pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
+/// Set to the vendor flag if we are building for the VNDK, 0 otherwise
+pub const FLAG_PRIVATE_LOCAL: TransactionFlags = sys::FLAG_PRIVATE_LOCAL;
+
+/// Internal interface of binder local or remote objects for making
+/// transactions.
///
-/// This trait corresponds to the interface of the C++ `IBinder` class.
-pub trait IBinder {
- /// First transaction code available for user commands (inclusive)
- const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION;
- /// Last transaction code available for user commands (inclusive)
- const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION;
-
- /// Corresponds to TF_ONE_WAY -- an asynchronous call.
- const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
- /// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
- const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
-
+/// This trait corresponds to the parts of the interface of the C++ `IBinder`
+/// class which are internal implementation details.
+pub trait IBinderInternal: IBinder {
/// Is this object still alive?
fn is_binder_alive(&self) -> bool;
@@ -122,19 +146,24 @@
/// * `data` - [`Parcel`] with input data
/// * `reply` - Optional [`Parcel`] for reply data
/// * `flags` - Transaction flags, e.g. marking the transaction as
- /// asynchronous ([`FLAG_ONEWAY`](IBinder::FLAG_ONEWAY))
+ /// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
&self,
code: TransactionCode,
flags: TransactionFlags,
input_callback: F,
) -> Result<Parcel>;
+}
+/// Interface of binder local or remote objects.
+///
+/// This trait corresponds to the parts of the interface of the C++ `IBinder`
+/// class which are public.
+pub trait IBinder {
/// Register the recipient for a notification if this binder
/// goes away. If this binder object unexpectedly goes away
/// (typically because its hosting process has been killed),
- /// then DeathRecipient::binder_died() will be called with a reference
- /// to this.
+ /// then the `DeathRecipient`'s callback will be called.
///
/// You will only receive death notifications for remote binders,
/// as local binders by definition can't die without you dying as well.
@@ -142,11 +171,6 @@
/// INVALID_OPERATION code being returned and nothing happening.
///
/// This link always holds a weak reference to its recipient.
- ///
- /// You will only receive a weak reference to the dead
- /// binder. You should not try to promote this to a strong reference.
- /// (Nor should you need to, as there is nothing useful you can
- /// directly do with it now that it has passed on.)
fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
/// Remove a previously registered death notification.
@@ -222,7 +246,8 @@
// the number of u16 elements before the null terminator.
let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
- CStr::from_ptr(raw_descriptor).to_str()
+ CStr::from_ptr(raw_descriptor)
+ .to_str()
.expect("Expected valid UTF-8 string from AIBinder_Class_getDescriptor")
.into()
}
@@ -523,6 +548,28 @@
}
}
+/// The features to enable when creating a native Binder.
+///
+/// This should always be initialised with a default value, e.g.:
+/// ```
+/// # use binder::BinderFeatures;
+/// BinderFeatures {
+/// set_requesting_sid: true,
+/// ..BinderFeatures::default(),
+/// }
+/// ```
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
+pub struct BinderFeatures {
+ /// Indicates that the service intends to receive caller security contexts. This must be true
+ /// for `ThreadState::with_calling_sid` to work.
+ pub set_requesting_sid: bool,
+ // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility
+ // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct
+ // expressions entirely.
+ #[doc(hidden)]
+ pub _non_exhaustive: (),
+}
+
/// Declare typed interfaces for a binder object.
///
/// Given an interface trait and descriptor string, create a native and remote
@@ -599,6 +646,23 @@
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
+ stability: $crate::Stability::default(),
+ }
+ }
+ };
+
+ {
+ $interface:path[$descriptor:expr] {
+ native: $native:ident($on_transact:path),
+ proxy: $proxy:ident,
+ stability: $stability:expr,
+ }
+ } => {
+ $crate::declare_binder_interface! {
+ $interface[$descriptor] {
+ native: $native($on_transact),
+ proxy: $proxy {},
+ stability: $stability,
}
}
};
@@ -613,12 +677,33 @@
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
+ native: $native($on_transact),
+ proxy: $proxy {
+ $($fname: $fty = $finit),*
+ },
+ stability: $crate::Stability::default(),
+ }
+ }
+ };
+
+ {
+ $interface:path[$descriptor:expr] {
+ native: $native:ident($on_transact:path),
+ proxy: $proxy:ident {
+ $($fname:ident: $fty:ty = $finit:expr),*
+ },
+ stability: $stability:expr,
+ }
+ } => {
+ $crate::declare_binder_interface! {
+ $interface[$descriptor] {
@doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")]
native: $native($on_transact),
@doc[concat!("A binder [`Proxy`]($crate::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
proxy: $proxy {
$($fname: $fty = $finit),*
},
+ stability: $stability,
}
}
};
@@ -632,6 +717,8 @@
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
+
+ stability: $stability:expr,
}
} => {
#[doc = $proxy_doc]
@@ -665,8 +752,9 @@
impl $native {
/// Create a new binder service.
- pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
- let binder = $crate::Binder::new($native(Box::new(inner)));
+ pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
+ let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+ $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
$crate::Strong::new(Box::new(binder))
}
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 43a237a..2694cba 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,8 +107,9 @@
pub mod parcel;
pub use crate::binder::{
- FromIBinder, IBinder, Interface, InterfaceClass, Remotable, Strong, TransactionCode,
- TransactionFlags, Weak,
+ BinderFeatures, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
+ Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION,
+ FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
@@ -123,8 +124,8 @@
pub use super::parcel::ParcelFileDescriptor;
pub use super::{add_service, get_interface};
pub use super::{
- ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState,
- Weak, WpIBinder,
+ BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
+ Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 185645e..3b3fd08 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode};
+use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode};
use crate::error::{status_result, status_t, Result, StatusCode};
use crate::parcel::{Parcel, Serialize};
use crate::proxy::SpIBinder;
@@ -49,11 +49,19 @@
unsafe impl<T: Remotable> Send for Binder<T> {}
impl<T: Remotable> Binder<T> {
- /// Create a new Binder remotable object.
+ /// Create a new Binder remotable object with default stability
///
/// This moves the `rust_object` into an owned [`Box`] and Binder will
/// manage its lifetime.
pub fn new(rust_object: T) -> Binder<T> {
+ Self::new_with_stability(rust_object, Stability::default())
+ }
+
+ /// Create a new Binder remotable object with the given stability
+ ///
+ /// This moves the `rust_object` into an owned [`Box`] and Binder will
+ /// manage its lifetime.
+ pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
let class = T::get_class();
let rust_object = Box::into_raw(Box::new(rust_object));
let ibinder = unsafe {
@@ -65,10 +73,12 @@
// ends.
sys::AIBinder_new(class.into(), rust_object as *mut c_void)
};
- Binder {
+ let mut binder = Binder {
ibinder,
rust_object,
- }
+ };
+ binder.mark_stability(stability);
+ binder
}
/// Set the extension of a binder interface. This allows a downstream
@@ -161,6 +171,42 @@
pub fn get_descriptor() -> &'static str {
T::get_descriptor()
}
+
+ /// Mark this binder object with the given stability guarantee
+ fn mark_stability(&mut self, stability: Stability) {
+ match stability {
+ Stability::Local => self.mark_local_stability(),
+ Stability::Vintf => {
+ unsafe {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
+ sys::AIBinder_markVintfStability(self.as_native_mut());
+ }
+ }
+ }
+ }
+
+ /// Mark this binder object with local stability, which is vendor if we are
+ /// building for the VNDK and system otherwise.
+ #[cfg(vendor_ndk)]
+ fn mark_local_stability(&mut self) {
+ unsafe {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
+ sys::AIBinder_markVendorStability(self.as_native_mut());
+ }
+ }
+
+ /// Mark this binder object with local stability, which is vendor if we are
+ /// building for the VNDK and system otherwise.
+ #[cfg(not(vendor_ndk))]
+ fn mark_local_stability(&mut self) {
+ unsafe {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
+ sys::AIBinder_markSystemStability(self.as_native_mut());
+ }
+ }
}
impl<T: Remotable> Interface for Binder<T> {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 132e075..52036f5 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -17,7 +17,8 @@
//! Rust API for interacting with a remote binder service.
use crate::binder::{
- AsNative, FromIBinder, IBinder, Interface, InterfaceClass, Strong, TransactionCode, TransactionFlags,
+ AsNative, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Strong,
+ TransactionCode, TransactionFlags,
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
@@ -26,8 +27,8 @@
};
use crate::sys;
-use std::convert::TryInto;
use std::cmp::Ordering;
+use std::convert::TryInto;
use std::ffi::{c_void, CString};
use std::fmt;
use std::os::unix::io::AsRawFd;
@@ -211,7 +212,7 @@
}
}
-impl<T: AsNative<sys::AIBinder>> IBinder for T {
+impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
/// Perform a binder transaction
fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
&self,
@@ -300,9 +301,7 @@
}
fn set_requesting_sid(&mut self, enable: bool) {
- unsafe {
- sys::AIBinder_setRequestingSid(self.as_native_mut(), enable)
- };
+ unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
}
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
@@ -351,7 +350,9 @@
status_result(status)?;
Ok(ibinder)
}
+}
+impl<T: AsNative<sys::AIBinder>> IBinder for T {
fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
status_result(unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -472,7 +473,10 @@
// WpIBinder object from it.
sys::AIBinder_Weak_clone(self.0)
};
- assert!(!ptr.is_null(), "Unexpected null pointer from AIBinder_Weak_clone");
+ assert!(
+ !ptr.is_null(),
+ "Unexpected null pointer from AIBinder_Weak_clone"
+ );
Self(ptr)
}
}
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index ef142b5..65fa2ca 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -21,6 +21,7 @@
#include <android/binder_parcel_platform.h>
#include <android/binder_process.h>
#include <android/binder_shell.h>
+#include <android/binder_stability.h>
#include <android/binder_status.h>
namespace android {
@@ -80,6 +81,7 @@
enum {
FLAG_ONEWAY = FLAG_ONEWAY,
FLAG_CLEAR_BUF = FLAG_CLEAR_BUF,
+ FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_LOCAL,
};
} // namespace consts
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 0bf76c6..607860f 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -114,8 +114,8 @@
source_stem: "bindings",
cpp_std: "gnu++17",
bindgen_flags: [
- "--whitelist-type", "Transaction",
- "--whitelist-var", "TESTDATA_.*",
+ "--allowlist-type", "Transaction",
+ "--allowlist-var", "TESTDATA_.*",
],
shared_libs: [
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 719229c..0332007 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -18,7 +18,10 @@
use binder::declare_binder_interface;
use binder::parcel::Parcel;
-use binder::{Binder, IBinder, Interface, SpIBinder, StatusCode, ThreadState, TransactionCode};
+use binder::{
+ Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
+ FIRST_CALL_TRANSACTION,
+};
use std::convert::{TryFrom, TryInto};
/// Name of service runner.
@@ -52,7 +55,8 @@
})));
service.set_requesting_sid(true);
if let Some(extension_name) = extension_name {
- let extension = BnTest::new_binder(TestService { s: extension_name });
+ let extension =
+ BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default());
service
.set_extension(&mut extension.as_binder())
.expect("Could not add extension");
@@ -83,7 +87,7 @@
#[repr(u32)]
enum TestTransactionCode {
- Test = SpIBinder::FIRST_CALL_TRANSACTION,
+ Test = FIRST_CALL_TRANSACTION,
GetSelinuxContext,
}
@@ -196,7 +200,6 @@
impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
-
#[cfg(test)]
mod tests {
use selinux_bindgen as selinux_sys;
@@ -209,9 +212,12 @@
use std::thread;
use std::time::Duration;
- use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong};
+ use binder::{
+ Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface,
+ SpIBinder, StatusCode, Strong,
+ };
- use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
+ use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
pub struct ScopedServiceProcess(Child);
@@ -290,7 +296,9 @@
};
assert_eq!(
test_client.get_selinux_context().unwrap(),
- expected_context.to_str().expect("context was invalid UTF-8"),
+ expected_context
+ .to_str()
+ .expect("context was invalid UTF-8"),
);
}
@@ -479,18 +487,25 @@
// This should succeed although we will have to treat the service as
// remote.
- let _interface: Strong<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
- .expect("Could not re-interpret service as the ITestSameDescriptor interface");
+ let _interface: Strong<dyn ITestSameDescriptor> =
+ FromIBinder::try_from(service.as_binder())
+ .expect("Could not re-interpret service as the ITestSameDescriptor interface");
}
/// Test that we can round-trip a rust service through a generic IBinder
#[test]
fn reassociate_rust_binder() {
let service_name = "testing_service";
- let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
- .as_binder();
+ let service_ibinder = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ )
+ .as_binder();
- let service: Strong<dyn ITest> = service_ibinder.into_interface()
+ let service: Strong<dyn ITest> = service_ibinder
+ .into_interface()
.expect("Could not reassociate the generic ibinder");
assert_eq!(service.test().unwrap(), service_name);
@@ -499,7 +514,12 @@
#[test]
fn weak_binder_upgrade() {
let service_name = "testing_service";
- let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+ let service = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ );
let weak = Strong::downgrade(&service);
@@ -512,7 +532,12 @@
fn weak_binder_upgrade_dead() {
let service_name = "testing_service";
let weak = {
- let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+ let service = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ );
Strong::downgrade(&service)
};
@@ -523,7 +548,12 @@
#[test]
fn weak_binder_clone() {
let service_name = "testing_service";
- let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+ let service = BnTest::new_binder(
+ TestService {
+ s: service_name.to_string(),
+ },
+ BinderFeatures::default(),
+ );
let weak = Strong::downgrade(&service);
let cloned = weak.clone();
@@ -539,8 +569,18 @@
#[test]
#[allow(clippy::eq_op)]
fn binder_ord() {
- let service1 = BnTest::new_binder(TestService { s: "testing_service1".to_string() });
- let service2 = BnTest::new_binder(TestService { s: "testing_service2".to_string() });
+ let service1 = BnTest::new_binder(
+ TestService {
+ s: "testing_service1".to_string(),
+ },
+ BinderFeatures::default(),
+ );
+ let service2 = BnTest::new_binder(
+ TestService {
+ s: "testing_service2".to_string(),
+ },
+ BinderFeatures::default(),
+ );
assert!(!(service1 < service1));
assert!(!(service1 > service1));
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index ce75ab7..4702e45 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -16,15 +16,13 @@
//! Rust Binder NDK interop tests
-use std::ffi::CStr;
-use std::os::raw::{c_char, c_int};
-use ::IBinderRustNdkInteropTest::binder::{self, Interface, StatusCode};
use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{
BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest,
};
-use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::{
- IBinderRustNdkInteropTestOther,
-};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::IBinderRustNdkInteropTestOther;
+use ::IBinderRustNdkInteropTest::binder::{self, BinderFeatures, Interface, StatusCode};
+use std::ffi::CStr;
+use std::os::raw::{c_char, c_int};
/// Look up the provided AIDL service and call its echo method.
///
@@ -37,18 +35,21 @@
// The Rust class descriptor pointer will not match the NDK one, but the
// descriptor strings match so this needs to still associate.
- let service: binder::Strong<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
- Err(e) => {
- eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
- return StatusCode::NAME_NOT_FOUND as c_int;
- }
- Ok(service) => service,
- };
+ let service: binder::Strong<dyn IBinderRustNdkInteropTest> =
+ match binder::get_interface(service_name) {
+ Err(e) => {
+ eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
+ return StatusCode::NAME_NOT_FOUND as c_int;
+ }
+ Ok(service) => service,
+ };
match service.echo("testing") {
- Ok(s) => if s != "testing" {
- return StatusCode::BAD_VALUE as c_int;
- },
+ Ok(s) => {
+ if s != "testing" {
+ return StatusCode::BAD_VALUE as c_int;
+ }
+ }
Err(e) => return e.into(),
}
@@ -88,7 +89,7 @@
#[no_mangle]
pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
let service_name = CStr::from_ptr(service_name).to_str().unwrap();
- let service = BnBinderRustNdkInteropTest::new_binder(Service);
+ let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
match binder::add_service(&service_name, service.as_binder()) {
Ok(_) => StatusCode::OK as c_int,
Err(e) => e as c_int,
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index f1b068e..66ba846 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -18,11 +18,11 @@
//! access.
use binder::declare_binder_interface;
+use binder::parcel::ParcelFileDescriptor;
use binder::{
- Binder, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+ Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
StatusCode, TransactionCode,
};
-use binder::parcel::ParcelFileDescriptor;
use std::ffi::{c_void, CStr, CString};
use std::sync::Once;
@@ -85,7 +85,7 @@
pub extern "C" fn rust_service() -> *mut c_void {
unsafe {
SERVICE_ONCE.call_once(|| {
- SERVICE = Some(BnReadParcelTest::new_binder(()).as_binder());
+ SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
});
SERVICE.as_ref().unwrap().as_raw().cast()
}
@@ -108,8 +108,12 @@
impl ReadParcelTest for () {}
#[allow(clippy::float_cmp)]
-fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode,
- parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
+fn on_transact(
+ _service: &dyn ReadParcelTest,
+ code: TransactionCode,
+ parcel: &Parcel,
+ reply: &mut Parcel,
+) -> Result<()> {
match code {
bindings::Transaction_TEST_BOOL => {
assert_eq!(parcel.read::<bool>()?, true);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 3bbb0b5..f303b7c 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -104,6 +104,74 @@
require_root: true,
}
+aidl_interface {
+ name: "binderRpcTestIface",
+ host_supported: true,
+ unstable: true,
+ srcs: [
+ "IBinderRpcSession.aidl",
+ "IBinderRpcTest.aidl",
+ ],
+ backend: {
+ java: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test {
+ name: "binderRpcTest",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ defaults: [
+ "binder_test_defaults",
+ "libbinder_ndk_host_user",
+ ],
+
+ srcs: [
+ "binderRpcTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "liblog",
+ ],
+ static_libs: [
+ "binderRpcTestIface-cpp",
+ "binderRpcTestIface-ndk_platform",
+ ],
+ test_suites: ["general-tests"],
+ require_root: true,
+}
+
+cc_benchmark {
+ name: "binderRpcBenchmark",
+ defaults: ["binder_test_defaults"],
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "binderRpcBenchmark.cpp",
+ "IBinderRpcBenchmark.aidl",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+}
+
cc_test {
name: "binderThroughputTest",
defaults: ["binder_test_defaults"],
@@ -190,6 +258,11 @@
srcs: [
"IBinderStabilityTest.aidl",
],
+ backend: {
+ java: {
+ enabled: false,
+ },
+ },
}
cc_test {
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/IBinderRpcBenchmark.aidl
similarity index 69%
copy from libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
copy to libs/binder/tests/IBinderRpcBenchmark.aidl
index b92a6a9..1457422 100644
--- a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,11 +14,7 @@
* limitations under the License.
*/
-#pragma once
-
-#include <binder/Parcel.h>
-#include <fuzzer/FuzzedDataProvider.h>
-
-namespace android {
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-} // namespace android
+interface IBinderRpcBenchmark {
+ @utf8InCpp String repeatString(@utf8InCpp String str);
+ IBinder repeatBinder(IBinder binder);
+}
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/IBinderRpcSession.aidl
similarity index 75%
copy from libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
copy to libs/binder/tests/IBinderRpcSession.aidl
index b92a6a9..cf5f318 100644
--- a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/IBinderRpcSession.aidl
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-#pragma once
-
-#include <binder/Parcel.h>
-#include <fuzzer/FuzzedDataProvider.h>
-
-namespace android {
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-} // namespace android
+interface IBinderRpcSession {
+ @utf8InCpp String getName();
+}
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
new file mode 100644
index 0000000..2bdb264
--- /dev/null
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IBinderRpcTest {
+ oneway void sendString(@utf8InCpp String str);
+ @utf8InCpp String doubleString(@utf8InCpp String str);
+
+ // number of known RPC binders to process, RpcState::countBinders
+ int countBinders();
+
+ // Caller sends server, callee pings caller's server and returns error code.
+ int pingMe(IBinder binder);
+ @nullable IBinder repeatBinder(@nullable IBinder binder);
+
+ void holdBinder(@nullable IBinder binder);
+ @nullable IBinder getHeldBinder();
+
+ // Idea is client creates its own instance of IBinderRpcTest and calls this,
+ // and the server calls 'binder' with (calls - 1) passing itself as 'binder',
+ // going back and forth until calls = 0
+ void nestMe(IBinderRpcTest binder, int calls);
+
+ // should always return the same binder
+ IBinder alwaysGiveMeTheSameBinder();
+
+ // Idea is that the server will not hold onto the session, the remote connection
+ // object must. This is to test lifetimes of binder objects, and consequently, also
+ // identity (since by assigning sessions names, we can make sure a section always
+ // references the session it was originally opened with).
+ IBinderRpcSession openSession(@utf8InCpp String name);
+
+ // Decremented in ~IBinderRpcSession
+ int getNumOpenSessions();
+
+ // primitives to test threading behavior
+ void lock();
+ oneway void unlockInMsAsync(int ms);
+ void lockUnlock(); // locks and unlocks a mutex
+
+ // take up binder thread for some time
+ void sleepMs(int ms);
+ oneway void sleepMsAsync(int ms);
+
+ void die(boolean cleanup);
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e2193fa..dc8c0f1 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -88,6 +88,7 @@
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_ECHO_VECTOR,
BINDER_LIB_TEST_REJECT_BUF,
+ BINDER_LIB_TEST_CAN_GET_SID,
};
pid_t start_server_process(int arg2, bool usePoll = false)
@@ -1192,6 +1193,14 @@
EXPECT_NE(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, GotSid) {
+ sp<IBinder> server = addServer();
+
+ Parcel data;
+ status_t ret = server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr);
+ EXPECT_EQ(OK, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -1494,6 +1503,9 @@
case BINDER_LIB_TEST_REJECT_BUF: {
return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR;
}
+ case BINDER_LIB_TEST_CAN_GET_SID: {
+ return IPCThreadState::self()->getCallingSid() == nullptr ? BAD_VALUE : NO_ERROR;
+ }
default:
return UNKNOWN_TRANSACTION;
};
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
new file mode 100644
index 0000000..7c82226
--- /dev/null
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#include <BnBinderRpcBenchmark.h>
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+#include <binder/Binder.h>
+#include <binder/RpcConnection.h>
+#include <binder/RpcServer.h>
+
+#include <thread>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+using android::BBinder;
+using android::IBinder;
+using android::interface_cast;
+using android::OK;
+using android::RpcConnection;
+using android::RpcServer;
+using android::sp;
+using android::binder::Status;
+
+class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
+ Status repeatString(const std::string& str, std::string* out) override {
+ *out = str;
+ return Status::ok();
+ }
+ Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override {
+ *out = str;
+ return Status::ok();
+ }
+};
+
+static sp<RpcConnection> gConnection = RpcConnection::make();
+
+void BM_getRootObject(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ CHECK(gConnection->getRootObject() != nullptr);
+ }
+}
+BENCHMARK(BM_getRootObject);
+
+void BM_pingTransaction(benchmark::State& state) {
+ sp<IBinder> binder = gConnection->getRootObject();
+ CHECK(binder != nullptr);
+
+ while (state.KeepRunning()) {
+ CHECK_EQ(OK, binder->pingBinder());
+ }
+}
+BENCHMARK(BM_pingTransaction);
+
+void BM_repeatString(benchmark::State& state) {
+ sp<IBinder> binder = gConnection->getRootObject();
+ CHECK(binder != nullptr);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ // Googlers might see go/another-look-at-aidl-hidl-perf
+ //
+ // When I checked in July 2019, 99.5% of AIDL transactions and 99.99% of HIDL
+ // transactions were less than one page in size (system wide during a test
+ // involving media and camera). This is why this diverges from
+ // binderThroughputTest and hwbinderThroughputTest. Future consideration - get
+ // this data on continuous integration. Here we are testing sending a
+ // transaction of twice this size. In other cases, we should focus on
+ // benchmarks of particular usecases. If individual binder transactions like
+ // the ones tested here are fast, then Android performance will be dominated
+ // by how many binder calls work together (and by factors like the scheduler,
+ // thermal throttling, core choice, etc..).
+ std::string str = std::string(getpagesize() * 2, 'a');
+ CHECK_EQ(str.size(), getpagesize() * 2);
+
+ while (state.KeepRunning()) {
+ std::string out;
+ Status ret = iface->repeatString(str, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_repeatString);
+
+void BM_repeatBinder(benchmark::State& state) {
+ sp<IBinder> binder = gConnection->getRootObject();
+ CHECK(binder != nullptr);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ while (state.KeepRunning()) {
+ // force creation of a new address
+ sp<IBinder> binder = sp<BBinder>::make();
+
+ sp<IBinder> out;
+ Status ret = iface->repeatBinder(binder, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_repeatBinder);
+
+int main(int argc, char** argv) {
+ ::benchmark::Initialize(&argc, argv);
+ if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+
+ std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
+ (void)unlink(addr.c_str());
+
+ std::thread([addr]() {
+ sp<RpcServer> server = RpcServer::make();
+ server->setRootObject(sp<MyBinderRpcBenchmark>::make());
+
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+ sp<RpcConnection> connection = server->addClientConnection();
+ CHECK(connection->setupUnixDomainServer(addr.c_str()));
+
+ connection->join();
+ }).detach();
+
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ if (gConnection->addUnixDomainClient(addr.c_str())) goto success;
+ }
+ LOG(FATAL) << "Could not connect.";
+success:
+
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
new file mode 100644
index 0000000..dd68fdb
--- /dev/null
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -0,0 +1,900 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BnBinderRpcSession.h>
+#include <BnBinderRpcTest.h>
+#include <aidl/IBinderRpcTest.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_libbinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcConnection.h>
+#include <binder/RpcServer.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <iostream>
+#include <thread>
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif //__BIONIC__
+
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "../RpcState.h" // for debugging
+
+namespace android {
+
+TEST(BinderRpcParcel, EntireParcelFormatted) {
+ Parcel p;
+ p.writeInt32(3);
+
+ EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
+}
+
+using android::binder::Status;
+
+#define EXPECT_OK(status) \
+ do { \
+ Status stat = (status); \
+ EXPECT_TRUE(stat.isOk()) << stat; \
+ } while (false)
+
+class MyBinderRpcSession : public BnBinderRpcSession {
+public:
+ static std::atomic<int32_t> gNum;
+
+ MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
+ Status getName(std::string* name) override {
+ *name = mName;
+ return Status::ok();
+ }
+ ~MyBinderRpcSession() { gNum--; }
+
+private:
+ std::string mName;
+};
+std::atomic<int32_t> MyBinderRpcSession::gNum;
+
+class MyBinderRpcTest : public BnBinderRpcTest {
+public:
+ sp<RpcConnection> connection;
+
+ Status sendString(const std::string& str) override {
+ (void)str;
+ return Status::ok();
+ }
+ Status doubleString(const std::string& str, std::string* strstr) override {
+ *strstr = str + str;
+ return Status::ok();
+ }
+ Status countBinders(int32_t* out) override {
+ if (connection == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ *out = connection->state()->countBinders();
+ if (*out != 1) {
+ connection->state()->dump();
+ }
+ return Status::ok();
+ }
+ Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
+ if (binder == nullptr) {
+ std::cout << "Received null binder!" << std::endl;
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ *out = binder->pingBinder();
+ return Status::ok();
+ }
+ Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+ *out = binder;
+ return Status::ok();
+ }
+ static sp<IBinder> mHeldBinder;
+ Status holdBinder(const sp<IBinder>& binder) override {
+ mHeldBinder = binder;
+ return Status::ok();
+ }
+ Status getHeldBinder(sp<IBinder>* held) override {
+ *held = mHeldBinder;
+ return Status::ok();
+ }
+ Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
+ if (count <= 0) return Status::ok();
+ return binder->nestMe(this, count - 1);
+ }
+ Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
+ static sp<IBinder> binder = new BBinder;
+ *out = binder;
+ return Status::ok();
+ }
+ Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
+ *out = new MyBinderRpcSession(name);
+ return Status::ok();
+ }
+ Status getNumOpenSessions(int32_t* out) override {
+ *out = MyBinderRpcSession::gNum;
+ return Status::ok();
+ }
+
+ std::mutex blockMutex;
+ Status lock() override {
+ blockMutex.lock();
+ return Status::ok();
+ }
+ Status unlockInMsAsync(int32_t ms) override {
+ usleep(ms * 1000);
+ blockMutex.unlock();
+ return Status::ok();
+ }
+ Status lockUnlock() override {
+ std::lock_guard<std::mutex> _l(blockMutex);
+ return Status::ok();
+ }
+
+ Status sleepMs(int32_t ms) override {
+ usleep(ms * 1000);
+ return Status::ok();
+ }
+
+ Status sleepMsAsync(int32_t ms) override {
+ // In-process binder calls are asynchronous, but the call to this method
+ // is synchronous wrt its client. This in/out-process threading model
+ // diffentiation is a classic binder leaky abstraction (for better or
+ // worse) and is preserved here the way binder sockets plugs itself
+ // into BpBinder, as nothing is changed at the higher levels
+ // (IInterface) which result in this behavior.
+ return sleepMs(ms);
+ }
+
+ Status die(bool cleanup) override {
+ if (cleanup) {
+ exit(1);
+ } else {
+ _exit(1);
+ }
+ }
+};
+sp<IBinder> MyBinderRpcTest::mHeldBinder;
+
+class Process {
+public:
+ Process(const std::function<void()>& f) {
+ if (0 == (mPid = fork())) {
+ // racey: assume parent doesn't crash before this is set
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ f();
+ }
+ }
+ ~Process() {
+ if (mPid != 0) {
+ kill(mPid, SIGKILL);
+ }
+ }
+
+private:
+ pid_t mPid = 0;
+};
+
+static std::string allocateSocketAddress() {
+ static size_t id = 0;
+ std::string temp = getenv("TMPDIR") ?: "/tmp";
+ return temp + "/binderRpcTest_" + std::to_string(id++);
+};
+
+struct ProcessConnection {
+ // reference to process hosting a socket server
+ Process host;
+
+ // client connection object associated with other process
+ sp<RpcConnection> connection;
+
+ // pre-fetched root object
+ sp<IBinder> rootBinder;
+
+ // whether connection should be invalidated by end of run
+ bool expectInvalid = false;
+
+ ~ProcessConnection() {
+ rootBinder = nullptr;
+ EXPECT_NE(nullptr, connection);
+ EXPECT_NE(nullptr, connection->state());
+ EXPECT_EQ(0, connection->state()->countBinders()) << (connection->state()->dump(), "dump:");
+
+ wp<RpcConnection> weakConnection = connection;
+ connection = nullptr;
+ EXPECT_EQ(nullptr, weakConnection.promote()) << "Leaked connection";
+ }
+};
+
+// Process connection where the process hosts IBinderRpcTest, the server used
+// for most testing here
+struct BinderRpcTestProcessConnection {
+ ProcessConnection proc;
+
+ // pre-fetched root object
+ sp<IBinder> rootBinder;
+
+ // pre-casted root object
+ sp<IBinderRpcTest> rootIface;
+
+ ~BinderRpcTestProcessConnection() {
+ if (!proc.expectInvalid) {
+ int32_t remoteBinders = 0;
+ EXPECT_OK(rootIface->countBinders(&remoteBinders));
+ // should only be the root binder object, iface
+ EXPECT_EQ(remoteBinders, 1);
+ }
+
+ rootIface = nullptr;
+ rootBinder = nullptr;
+ }
+};
+
+enum class SocketType {
+ UNIX,
+#ifdef __BIONIC__
+ VSOCK,
+#endif // __BIONIC__
+ INET,
+};
+static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
+ switch (info.param) {
+ case SocketType::UNIX:
+ return "unix_domain_socket";
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ return "vm_socket";
+#endif // __BIONIC__
+ case SocketType::INET:
+ return "inet_socket";
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ return "";
+ }
+}
+class BinderRpc : public ::testing::TestWithParam<SocketType> {
+public:
+ // This creates a new process serving an interface on a certain number of
+ // threads.
+ ProcessConnection createRpcTestSocketServerProcess(
+ size_t numThreads,
+ const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
+ CHECK_GT(numThreads, 0);
+
+ SocketType socketType = GetParam();
+
+ std::string addr = allocateSocketAddress();
+ unlink(addr.c_str());
+ static unsigned int port = 3456;
+ port++;
+
+ auto ret = ProcessConnection{
+ .host = Process([&] {
+ sp<RpcServer> server = RpcServer::make();
+
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+ // server supporting one client on one socket
+ sp<RpcConnection> connection = server->addClientConnection();
+
+ switch (socketType) {
+ case SocketType::UNIX:
+ CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
+ break;
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ CHECK(connection->setupVsockServer(port));
+ break;
+#endif // __BIONIC__
+ case SocketType::INET:
+ CHECK(connection->setupInetServer(port));
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
+
+ configure(server, connection);
+
+ // accept 'numThreads' connections
+ std::vector<std::thread> pool;
+ for (size_t i = 0; i + 1 < numThreads; i++) {
+ pool.push_back(std::thread([=] { connection->join(); }));
+ }
+ connection->join();
+ for (auto& t : pool) t.join();
+ }),
+ .connection = RpcConnection::make(),
+ };
+
+ // create remainder of connections
+ for (size_t i = 0; i < numThreads; i++) {
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ switch (socketType) {
+ case SocketType::UNIX:
+ if (ret.connection->addUnixDomainClient(addr.c_str())) goto success;
+ break;
+#ifdef __BIONIC__
+ case SocketType::VSOCK:
+ if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success;
+ break;
+#endif // __BIONIC__
+ case SocketType::INET:
+ if (ret.connection->addInetClient("127.0.0.1", port)) goto success;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unknown socket type");
+ }
+ }
+ LOG_ALWAYS_FATAL("Could not connect");
+ success:;
+ }
+
+ ret.rootBinder = ret.connection->getRootObject();
+ return ret;
+ }
+
+ BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
+ BinderRpcTestProcessConnection ret{
+ .proc = createRpcTestSocketServerProcess(numThreads,
+ [&](const sp<RpcServer>& server,
+ const sp<RpcConnection>& connection) {
+ sp<MyBinderRpcTest> service =
+ new MyBinderRpcTest;
+ server->setRootObject(service);
+ service->connection =
+ connection; // for testing only
+ }),
+ };
+
+ ret.rootBinder = ret.proc.rootBinder;
+ ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+ return ret;
+ }
+};
+
+TEST_P(BinderRpc, RootObjectIsNull) {
+ auto proc = createRpcTestSocketServerProcess(1,
+ [](const sp<RpcServer>& server,
+ const sp<RpcConnection>&) {
+ // this is the default, but to be explicit
+ server->setRootObject(nullptr);
+ });
+
+ // retrieved by getRootObject when process is created above
+ EXPECT_EQ(nullptr, proc.rootBinder);
+
+ // make sure we can retrieve it again (process doesn't crash)
+ EXPECT_EQ(nullptr, proc.connection->getRootObject());
+}
+
+TEST_P(BinderRpc, Ping) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+TEST_P(BinderRpc, GetInterfaceDescriptor) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ ASSERT_NE(proc.rootBinder, nullptr);
+ EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
+}
+
+TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ Parcel data;
+ Parcel reply;
+ EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, AppendSeparateFormats) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ Parcel p1;
+ p1.markForBinder(proc.rootBinder);
+ p1.writeInt32(3);
+
+ Parcel p2;
+
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
+ EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
+}
+
+TEST_P(BinderRpc, UnknownTransaction) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ Parcel data;
+ data.markForBinder(proc.rootBinder);
+ Parcel reply;
+ EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
+}
+
+TEST_P(BinderRpc, SendSomethingOneway) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ EXPECT_OK(proc.rootIface->sendString("asdf"));
+}
+
+TEST_P(BinderRpc, SendAndGetResultBack) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ std::string doubled;
+ EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
+TEST_P(BinderRpc, SendAndGetResultBackBig) {
+ auto proc = createRpcTestSocketServerProcess(1);
+ std::string single = std::string(1024, 'a');
+ std::string doubled;
+ EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
+ EXPECT_EQ(single + single, doubled);
+}
+
+TEST_P(BinderRpc, CallMeBack) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ int32_t pingResult;
+ EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
+ EXPECT_EQ(OK, pingResult);
+
+ EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatBinder) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> inBinder = new MyBinderRpcSession("foo");
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+ EXPECT_EQ(inBinder, outBinder);
+
+ wp<IBinder> weak = inBinder;
+ inBinder = nullptr;
+ outBinder = nullptr;
+
+ // Force reading a reply, to process any pending dec refs from the other
+ // process (the other process will process dec refs there before processing
+ // the ping here).
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ EXPECT_EQ(nullptr, weak.promote());
+
+ EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST_P(BinderRpc, RepeatTheirBinder) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+
+ sp<IBinder> inBinder = IInterface::asBinder(session);
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+ EXPECT_EQ(inBinder, outBinder);
+
+ wp<IBinder> weak = inBinder;
+ session = nullptr;
+ inBinder = nullptr;
+ outBinder = nullptr;
+
+ // Force reading a reply, to process any pending dec refs from the other
+ // process (the other process will process dec refs there before processing
+ // the ping here).
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, RepeatBinderNull) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
+ EXPECT_EQ(nullptr, outBinder);
+}
+
+TEST_P(BinderRpc, HoldBinder) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ IBinder* ptr = nullptr;
+ {
+ sp<IBinder> binder = new BBinder();
+ ptr = binder.get();
+ EXPECT_OK(proc.rootIface->holdBinder(binder));
+ }
+
+ sp<IBinder> held;
+ EXPECT_OK(proc.rootIface->getHeldBinder(&held));
+
+ EXPECT_EQ(held.get(), ptr);
+
+ // stop holding binder, because we test to make sure references are cleaned
+ // up
+ EXPECT_OK(proc.rootIface->holdBinder(nullptr));
+ // and flush ref counts
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+// START TESTS FOR LIMITATIONS OF SOCKET BINDER
+// These are behavioral differences form regular binder, where certain usecases
+// aren't supported.
+
+TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) {
+ auto proc1 = createRpcTestSocketServerProcess(1);
+ auto proc2 = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+ sp<IBinder> outBinder;
+ EXPECT_EQ(INVALID_OPERATION,
+ proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
+}
+
+TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ // for historical reasons, IServiceManager interface only returns the
+ // exception code
+ EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
+ defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
+}
+
+// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+
+TEST_P(BinderRpc, RepeatRootObject) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> outBinder;
+ EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
+ EXPECT_EQ(proc.rootBinder, outBinder);
+}
+
+TEST_P(BinderRpc, NestedTransactions) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ auto nastyNester = sp<MyBinderRpcTest>::make();
+ EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
+
+ wp<IBinder> weak = nastyNester;
+ nastyNester = nullptr;
+ EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST_P(BinderRpc, SameBinderEquality) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> a;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+
+ sp<IBinder> b;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+ EXPECT_EQ(a, b);
+}
+
+TEST_P(BinderRpc, SameBinderEqualityWeak) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinder> a;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+ wp<IBinder> weak = a;
+ a = nullptr;
+
+ sp<IBinder> b;
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+ // this is the wrong behavior, since BpBinder
+ // doesn't implement onIncStrongAttempted
+ // but make sure there is no crash
+ EXPECT_EQ(nullptr, weak.promote());
+
+ GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
+
+ // In order to fix this:
+ // - need to have incStrongAttempted reflected across IPC boundary (wait for
+ // response to promote - round trip...)
+ // - sendOnLastWeakRef, to delete entries out of RpcState table
+ EXPECT_EQ(b, weak.promote());
+}
+
+#define expectSessions(expected, iface) \
+ do { \
+ int session; \
+ EXPECT_OK((iface)->getNumOpenSessions(&session)); \
+ EXPECT_EQ(expected, session); \
+ } while (false)
+
+TEST_P(BinderRpc, SingleSession) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+ std::string out;
+ EXPECT_OK(session->getName(&out));
+ EXPECT_EQ("aoeu", out);
+
+ expectSessions(1, proc.rootIface);
+ session = nullptr;
+ expectSessions(0, proc.rootIface);
+}
+
+TEST_P(BinderRpc, ManySessions) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ std::vector<sp<IBinderRpcSession>> sessions;
+
+ for (size_t i = 0; i < 15; i++) {
+ expectSessions(i, proc.rootIface);
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
+ sessions.push_back(session);
+ }
+ expectSessions(sessions.size(), proc.rootIface);
+ for (size_t i = 0; i < sessions.size(); i++) {
+ std::string out;
+ EXPECT_OK(sessions.at(i)->getName(&out));
+ EXPECT_EQ(std::to_string(i), out);
+ }
+ expectSessions(sessions.size(), proc.rootIface);
+
+ while (!sessions.empty()) {
+ sessions.pop_back();
+ expectSessions(sessions.size(), proc.rootIface);
+ }
+ expectSessions(0, proc.rootIface);
+}
+
+size_t epochMillis() {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::seconds;
+ using std::chrono::system_clock;
+ return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+}
+
+TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+ constexpr size_t kNumThreads = 10;
+
+ auto proc = createRpcTestSocketServerProcess(kNumThreads);
+
+ EXPECT_OK(proc.rootIface->lock());
+
+ // block all but one thread taking locks
+ std::vector<std::thread> ts;
+ for (size_t i = 0; i < kNumThreads - 1; i++) {
+ ts.push_back(std::thread([&] { proc.rootIface->lockUnlock(); }));
+ }
+
+ usleep(100000); // give chance for calls on other threads
+
+ // other calls still work
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ constexpr size_t blockTimeMs = 500;
+ size_t epochMsBefore = epochMillis();
+ // after this, we should never see a response within this time
+ EXPECT_OK(proc.rootIface->unlockInMsAsync(blockTimeMs));
+
+ // this call should be blocked for blockTimeMs
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ size_t epochMsAfter = epochMillis();
+ EXPECT_GE(epochMsAfter, epochMsBefore + blockTimeMs) << epochMsBefore;
+
+ for (auto& t : ts) t.join();
+}
+
+TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+ constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumCalls = kNumThreads + 3;
+ constexpr size_t kSleepMs = 500;
+
+ auto proc = createRpcTestSocketServerProcess(kNumThreads);
+
+ size_t epochMsBefore = epochMillis();
+
+ std::vector<std::thread> ts;
+ for (size_t i = 0; i < kNumCalls; i++) {
+ ts.push_back(std::thread([&] { proc.rootIface->sleepMs(kSleepMs); }));
+ }
+
+ for (auto& t : ts) t.join();
+
+ size_t epochMsAfter = epochMillis();
+
+ EXPECT_GE(epochMsAfter, epochMsBefore + 2 * kSleepMs);
+
+ // Potential flake, but make sure calls are handled in parallel.
+ EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
+}
+
+TEST_P(BinderRpc, ThreadingStressTest) {
+ constexpr size_t kNumClientThreads = 10;
+ constexpr size_t kNumServerThreads = 10;
+ constexpr size_t kNumCalls = 100;
+
+ auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < kNumClientThreads; i++) {
+ threads.push_back(std::thread([&] {
+ for (size_t j = 0; j < kNumCalls; j++) {
+ sp<IBinder> out;
+ EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &out));
+ EXPECT_EQ(proc.rootBinder, out);
+ }
+ }));
+ }
+
+ for (auto& t : threads) t.join();
+}
+
+TEST_P(BinderRpc, OnewayStressTest) {
+ constexpr size_t kNumClientThreads = 10;
+ constexpr size_t kNumServerThreads = 10;
+ constexpr size_t kNumCalls = 100;
+
+ auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < kNumClientThreads; i++) {
+ threads.push_back(std::thread([&] {
+ for (size_t j = 0; j < kNumCalls; j++) {
+ EXPECT_OK(proc.rootIface->sendString("a"));
+ }
+
+ // check threads are not stuck
+ EXPECT_OK(proc.rootIface->sleepMs(250));
+ }));
+ }
+
+ for (auto& t : threads) t.join();
+}
+
+TEST_P(BinderRpc, OnewayCallDoesNotWait) {
+ constexpr size_t kReallyLongTimeMs = 100;
+ constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
+
+ // more than one thread, just so this doesn't deadlock
+ auto proc = createRpcTestSocketServerProcess(2);
+
+ size_t epochMsBefore = epochMillis();
+
+ EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
+
+ size_t epochMsAfter = epochMillis();
+ EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
+}
+
+TEST_P(BinderRpc, OnewayCallQueueing) {
+ constexpr size_t kNumSleeps = 10;
+ constexpr size_t kNumExtraServerThreads = 4;
+ constexpr size_t kSleepMs = 50;
+
+ // make sure calls to the same object happen on the same thread
+ auto proc = createRpcTestSocketServerProcess(1 + kNumExtraServerThreads);
+
+ EXPECT_OK(proc.rootIface->lock());
+
+ for (size_t i = 0; i < kNumSleeps; i++) {
+ // these should be processed serially
+ proc.rootIface->sleepMsAsync(kSleepMs);
+ }
+ // should also be processesed serially
+ EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
+
+ size_t epochMsBefore = epochMillis();
+ EXPECT_OK(proc.rootIface->lockUnlock());
+ size_t epochMsAfter = epochMillis();
+
+ EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+}
+
+TEST_P(BinderRpc, Die) {
+ for (bool doDeathCleanup : {true, false}) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ // make sure there is some state during crash
+ // 1. we hold their binder
+ sp<IBinderRpcSession> session;
+ EXPECT_OK(proc.rootIface->openSession("happy", &session));
+ // 2. they hold our binder
+ sp<IBinder> binder = new BBinder();
+ EXPECT_OK(proc.rootIface->holdBinder(binder));
+
+ EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
+ << "Do death cleanup: " << doDeathCleanup;
+
+ proc.proc.expectInvalid = true;
+ }
+}
+
+TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
+ ASSERT_NE(binder, nullptr);
+
+ ASSERT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+}
+
+TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
+ ASSERT_NE(binder, nullptr);
+
+ auto ndkBinder = aidl::IBinderRpcTest::fromBinder(binder);
+ ASSERT_NE(ndkBinder, nullptr);
+
+ std::string out;
+ ndk::ScopedAStatus status = ndkBinder->doubleString("aoeu", &out);
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
+ ASSERT_EQ("aoeuaoeu", out);
+}
+
+ssize_t countFds() {
+ DIR* dir = opendir("/proc/self/fd/");
+ if (dir == nullptr) return -1;
+ ssize_t ret = 0;
+ dirent* ent;
+ while ((ent = readdir(dir)) != nullptr) ret++;
+ closedir(dir);
+ return ret;
+}
+
+TEST_P(BinderRpc, Fds) {
+ ssize_t beforeFds = countFds();
+ ASSERT_GE(beforeFds, 0);
+ {
+ auto proc = createRpcTestSocketServerProcess(10);
+ ASSERT_EQ(OK, proc.rootBinder->pingBinder());
+ }
+ ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
+}
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+ ::testing::ValuesIn({
+ SocketType::UNIX,
+#ifdef __BIONIC__
+ SocketType::VSOCK,
+#endif // __BIONIC__
+ SocketType::INET,
+ }),
+ PrintSocketType);
+
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index ffb3ef2..c857d62 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -226,7 +226,7 @@
IncrementNativeHandle,
IncrementNoCopyNoMove,
IncrementParcelableVector,
- ToUpper,
+ DoubleString,
CallMeBack,
IncrementInt32,
IncrementUint32,
@@ -256,7 +256,7 @@
virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
virtual status_t increment(const std::vector<TestParcelable>& a,
std::vector<TestParcelable>* aPlusOne) const = 0;
- virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
+ virtual status_t doubleString(const String8& str, String8* doubleStr) const = 0;
// As mentioned above, sp<IBinder> is already tested by setDeathToken
virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
@@ -329,9 +329,10 @@
std::vector<TestParcelable>*);
return callRemote<Signature>(Tag::IncrementParcelableVector, a, aPlusOne);
}
- status_t toUpper(const String8& str, String8* upperStr) const override {
+ status_t doubleString(const String8& str, String8* doubleStr) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
- return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
+ return callRemote<decltype(&ISafeInterfaceTest::doubleString)>(Tag::DoubleString, str,
+ doubleStr);
}
void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
@@ -454,10 +455,9 @@
}
return NO_ERROR;
}
- status_t toUpper(const String8& str, String8* upperStr) const override {
+ status_t doubleString(const String8& str, String8* doubleStr) const override {
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
- *upperStr = str;
- upperStr->toUpper();
+ *doubleStr = str + str;
return NO_ERROR;
}
void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
@@ -548,8 +548,8 @@
std::vector<TestParcelable>*) const;
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
}
- case ISafeInterfaceTest::Tag::ToUpper: {
- return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
+ case ISafeInterfaceTest::Tag::DoubleString: {
+ return callLocal(data, reply, &ISafeInterfaceTest::doubleString);
}
case ISafeInterfaceTest::Tag::CallMeBack: {
return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
@@ -726,12 +726,12 @@
}
}
-TEST_F(SafeInterfaceTest, TestToUpper) {
- const String8 str{"Hello, world!"};
- String8 upperStr;
- status_t result = mSafeInterfaceTest->toUpper(str, &upperStr);
+TEST_F(SafeInterfaceTest, TestDoubleString) {
+ const String8 str{"asdf"};
+ String8 doubleStr;
+ status_t result = mSafeInterfaceTest->doubleString(str, &doubleStr);
ASSERT_EQ(NO_ERROR, result);
- ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"});
+ ASSERT_TRUE(doubleStr == String8{"asdfasdf"});
}
TEST_F(SafeInterfaceTest, TestCallMeBack) {
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 1f2779a..2ce13df 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android/binder_libbinder.h>
#include <android/binder_manager.h>
#include <android/binder_stability.h>
#include <binder/Binder.h>
@@ -131,6 +132,55 @@
EXPECT_TRUE(Stability::requiresVintfDeclaration(BadStableBinder::vintf()));
}
+TEST(BinderStability, ForceDowngradeToLocalStability) {
+ sp<IBinder> someBinder = BadStableBinder::vintf();
+
+ EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder));
+
+ // silly to do this after already using the binder, but it's for the test
+ Stability::forceDowngradeToLocalStability(someBinder);
+
+ EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder));
+}
+
+TEST(BinderStability, NdkForceDowngradeToLocalStability) {
+ sp<IBinder> someBinder = BadStableBinder::vintf();
+
+ EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder));
+
+ // silly to do this after already using the binder, but it's for the test
+ AIBinder_forceDowngradeToLocalStability(AIBinder_fromPlatformBinder(someBinder));
+
+ EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder));
+}
+
+TEST(BinderStability, ForceDowngradeToVendorStability) {
+ sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer);
+ auto server = interface_cast<IBinderStabilityTest>(serverBinder);
+
+ ASSERT_NE(nullptr, server.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(server)->remoteBinder());
+
+ {
+ sp<BadStableBinder> binder = BadStableBinder::vintf();
+
+ EXPECT_TRUE(Stability::requiresVintfDeclaration(binder));
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ sp<BadStableBinder> binder = BadStableBinder::vintf();
+
+ // This method should never be called directly. This is done only for the test.
+ Stability::forceDowngradeToVendorStability(binder);
+
+ // Binder downgraded to vendor stability, cannot be called from system context
+ EXPECT_FALSE(Stability::requiresVintfDeclaration(binder));
+ EXPECT_EQ(BAD_TYPE, server->sendAndCallBinder(binder).exceptionCode());
+ EXPECT_FALSE(binder->gotUserTransaction);
+ }
+}
+
TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
sp<IBinder> vintfServer = BadStableBinder::vintf();
@@ -142,6 +192,8 @@
EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+ EXPECT_EQ(std::nullopt, android::defaultServiceManager()->updatableViaApex(instance))
+ << instance8;
}
}
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
similarity index 100%
rename from libs/binder/parcel_fuzzer/Android.bp
rename to libs/binder/tests/parcel_fuzzer/Android.bp
diff --git a/libs/binder/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/binder.cpp
rename to libs/binder/tests/parcel_fuzzer/binder.cpp
diff --git a/libs/binder/parcel_fuzzer/binder.h b/libs/binder/tests/parcel_fuzzer/binder.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/binder.h
rename to libs/binder/tests/parcel_fuzzer/binder.h
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/binder_ndk.cpp
rename to libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.h b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
similarity index 97%
rename from libs/binder/parcel_fuzzer/binder_ndk.h
rename to libs/binder/tests/parcel_fuzzer/binder_ndk.h
index e69d9c1..cf24ab9 100644
--- a/libs/binder/parcel_fuzzer/binder_ndk.h
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
@@ -23,7 +23,7 @@
// libbinder_ndk doesn't export this header which breaks down its API for NDK
// and APEX users, but we need access to it to fuzz.
-#include "../ndk/parcel_internal.h"
+#include "../../ndk/parcel_internal.h"
class NdkParcelAdapter {
public:
diff --git a/libs/binder/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/hwbinder.cpp
rename to libs/binder/tests/parcel_fuzzer/hwbinder.cpp
diff --git a/libs/binder/parcel_fuzzer/hwbinder.h b/libs/binder/tests/parcel_fuzzer/hwbinder.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/hwbinder.h
rename to libs/binder/tests/parcel_fuzzer/hwbinder.h
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
rename to libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
similarity index 80%
rename from libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
rename to libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index b92a6a9..749bf21 100644
--- a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -20,5 +20,12 @@
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
+/**
+ * Fill parcel data, including some random binder objects and FDs
+ */
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
+/**
+ * Fill parcel data, but don't fill any objects.
+ */
+void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
} // namespace android
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
similarity index 89%
rename from libs/binder/parcel_fuzzer/main.cpp
rename to libs/binder/tests/parcel_fuzzer/main.cpp
index 78606cc..332e2ad 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -23,6 +23,7 @@
#include <iostream>
#include <android-base/logging.h>
+#include <binder/RpcConnection.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
@@ -32,6 +33,8 @@
#include <sys/time.h>
using android::fillRandomParcel;
+using android::RpcConnection;
+using android::sp;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
// TODO: functionality to create random parcels for libhwbinder parcels
@@ -56,7 +59,18 @@
provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
P p;
- fillRandomParcel(&p, std::move(provider));
+ if constexpr (std::is_same_v<P, android::Parcel>) {
+ if (provider.ConsumeBool()) {
+ auto connection = sp<RpcConnection>::make();
+ CHECK(connection->addNullDebuggingClient());
+ p.markForRpc(connection);
+ fillRandomParcelData(&p, std::move(provider));
+ } else {
+ fillRandomParcel(&p, std::move(provider));
+ }
+ } else {
+ fillRandomParcel(&p, std::move(provider));
+ }
// since we are only using a byte to index
CHECK(reads.size() <= 255) << reads.size();
diff --git a/libs/binder/parcel_fuzzer/parcel_fuzzer.h b/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/parcel_fuzzer.h
rename to libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
diff --git a/libs/binder/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/random_fd.cpp
rename to libs/binder/tests/parcel_fuzzer/random_fd.cpp
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
similarity index 93%
rename from libs/binder/parcel_fuzzer/random_parcel.cpp
rename to libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 9ca4c8a..b045a22 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -75,4 +75,9 @@
}
}
+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()));
+}
+
} // namespace android
diff --git a/libs/binder/parcel_fuzzer/util.cpp b/libs/binder/tests/parcel_fuzzer/util.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/util.cpp
rename to libs/binder/tests/parcel_fuzzer/util.cpp
diff --git a/libs/binder/parcel_fuzzer/util.h b/libs/binder/tests/parcel_fuzzer/util.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/util.h
rename to libs/binder/tests/parcel_fuzzer/util.h
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
similarity index 100%
rename from libs/binder/tests/fuzzers/Android.bp
rename to libs/binder/tests/unit_fuzzers/Android.bp
diff --git a/libs/binder/tests/fuzzers/BinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BinderFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/BinderFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/BinderFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/BinderFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/BpBinderFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/IBinderFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp b/libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp b/libs/binder/tests/unit_fuzzers/PersistableBundleFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/PersistableBundleFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/PersistableBundleFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/PersistableBundleFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/StabilityFuzz.cpp b/libs/binder/tests/unit_fuzzers/StabilityFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/StabilityFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/StabilityFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/StabilityFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/StabilityFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/StatusFuzz.cpp b/libs/binder/tests/unit_fuzzers/StatusFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/StatusFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/StatusFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/StatusFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/StatusFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/StatusFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/StatusFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/TextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/TextOutputFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/commonFuzzHelpers.h b/libs/binder/tests/unit_fuzzers/commonFuzzHelpers.h
similarity index 100%
rename from libs/binder/tests/fuzzers/commonFuzzHelpers.h
rename to libs/binder/tests/unit_fuzzers/commonFuzzHelpers.h
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 4ecbe53..761e45c 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -73,4 +73,9 @@
return out;
}
+std::optional<String16> ServiceManager::updatableViaApex(const String16& name) {
+ (void)name;
+ return std::nullopt;
+}
+
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 4ef47fb..e26c21b 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -19,6 +19,7 @@
#include <binder/IServiceManager.h>
#include <map>
+#include <optional>
namespace android {
@@ -48,6 +49,8 @@
Vector<String16> getDeclaredInstances(const String16& iface) override;
+ std::optional<String16> updatableViaApex(const String16& name) override;
+
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ec73ce..3030068 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -51,13 +51,13 @@
std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]"));
status_t err = gbuffer->initCheck();
- if (err != 0 || gbuffer->handle == 0) {
+ if (err != 0 || gbuffer->handle == nullptr) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
ALOGE("GraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
desc->width, desc->height, desc->layers, strerror(-err), gbuffer->handle);
- return err;
+ return err == 0 ? UNKNOWN_ERROR : err;
}
*outBuffer = AHardwareBuffer_from_GraphicBuffer(gbuffer.get());
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
new file mode 100644
index 0000000..a5712b3
--- /dev/null
+++ b/libs/permission/Android.bp
@@ -0,0 +1,23 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+ name: "libpermission",
+ srcs: [
+ "AppOpsManager.cpp",
+ "IAppOpsCallback.cpp",
+ "IAppOpsService.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/AppOpsManager.cpp b/libs/permission/AppOpsManager.cpp
similarity index 98%
rename from libs/binder/AppOpsManager.cpp
rename to libs/permission/AppOpsManager.cpp
index 1c6b491..f3ea1a7 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/permission/AppOpsManager.cpp
@@ -36,7 +36,7 @@
pthread_mutex_lock(&gClientIdMutex);
if (gClientId == nullptr) {
- gClientId = new BBinder();
+ gClientId = sp<BBinder>::make();
}
pthread_mutex_unlock(&gClientIdMutex);
return gClientId;
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/permission/IAppOpsCallback.cpp
similarity index 100%
rename from libs/binder/IAppOpsCallback.cpp
rename to libs/permission/IAppOpsCallback.cpp
diff --git a/libs/binder/IAppOpsService.cpp b/libs/permission/IAppOpsService.cpp
similarity index 100%
rename from libs/binder/IAppOpsService.cpp
rename to libs/permission/IAppOpsService.cpp
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
similarity index 100%
rename from libs/binder/include/binder/AppOpsManager.h
rename to libs/permission/include/binder/AppOpsManager.h
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/permission/include/binder/IAppOpsCallback.h
similarity index 100%
rename from libs/binder/include/binder/IAppOpsCallback.h
rename to libs/permission/include/binder/IAppOpsCallback.h
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h
similarity index 100%
rename from libs/binder/include/binder/IAppOpsService.h
rename to libs/permission/include/binder/IAppOpsService.h
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 497c33c..edd453a 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -48,11 +48,10 @@
"libutils",
"liblog",
"libhardware",
+ "libpermission",
],
export_include_dirs: ["include"],
- export_shared_lib_headers: ["libbinder", "libhardware"],
+ export_shared_lib_headers: ["libbinder", "libpermission", "libhardware"],
}
-
-subdirs = ["tests"]
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 2517060..6ea64b4 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -58,6 +58,7 @@
#include <sstream>
#include <android-base/chrono_utils.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <binder/Binder.h>
#include <input/InputDevice.h>
@@ -72,13 +73,14 @@
#define INDENT3 " "
#define INDENT4 " "
+using android::base::HwTimeoutMultiplier;
using android::base::StringPrintf;
namespace android::inputdispatcher {
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
-constexpr std::chrono::nanoseconds DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5s;
+const std::chrono::nanoseconds DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5s * HwTimeoutMultiplier();
// Amount of time to allow for all pending events to be processed when an app switch
// key is on the way. This is used to preempt input dispatch and drop input events
diff --git a/services/memtrackproxy/Android.bp b/services/memtrackproxy/Android.bp
new file mode 100644
index 0000000..7d78f3b
--- /dev/null
+++ b/services/memtrackproxy/Android.bp
@@ -0,0 +1,50 @@
+// 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+ name: "libmemtrackproxy",
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "android.hardware.memtrack@1.0",
+ "android.hardware.memtrack-V1-ndk_platform",
+ ],
+ srcs: [
+ "MemtrackProxy.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ local_include_dirs: [
+ "include/memtrackproxy",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.memtrack@1.0",
+ "android.hardware.memtrack-V1-ndk_platform",
+ ],
+}
diff --git a/services/memtrackproxy/MemtrackProxy.cpp b/services/memtrackproxy/MemtrackProxy.cpp
new file mode 100644
index 0000000..4676167
--- /dev/null
+++ b/services/memtrackproxy/MemtrackProxy.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+
+#include "MemtrackProxy.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <private/android_filesystem_config.h>
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace memtrack {
+
+// Check Memtrack Flags
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SMAPS_ACCOUNTED) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SMAPS_ACCOUNTED));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SMAPS_UNACCOUNTED) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SMAPS_UNACCOUNTED));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SHARED) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SHARED));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SHARED_PSS) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SHARED_PSS));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::PRIVATE) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_PRIVATE));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SYSTEM) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SYSTEM));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::DEDICATED) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_DEDICATED));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::NONSECURE) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_NONSECURE));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SECURE) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SECURE));
+
+// Check Memtrack Types
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::OTHER) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackType::OTHER));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::GL) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackType::GL));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::GRAPHICS) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackType::GRAPHICS));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::MULTIMEDIA) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackType::MULTIMEDIA));
+static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::CAMERA) ==
+ static_cast<uint32_t>(V1_aidl::MemtrackType::CAMERA));
+
+__attribute__((warn_unused_result)) bool translate(const V1_0_hidl::MemtrackRecord& in,
+ V1_aidl::MemtrackRecord* out) {
+ // Convert uint64_t to int64_t (long in AIDL). AIDL doesn't support unsigned types.
+ if (in.sizeInBytes > std::numeric_limits<int64_t>::max() || in.sizeInBytes < 0) {
+ return false;
+ }
+ out->sizeInBytes = static_cast<int64_t>(in.sizeInBytes);
+
+ // It's ok to just assign directly, since this is a bitmap.
+ out->flags = in.flags;
+ return true;
+}
+
+sp<V1_0_hidl::IMemtrack> MemtrackProxy::MemtrackHidlInstance() {
+ return V1_0_hidl::IMemtrack::getService();
+}
+
+std::shared_ptr<V1_aidl::IMemtrack> MemtrackProxy::MemtrackAidlInstance() {
+ const auto instance = std::string() + V1_aidl::IMemtrack::descriptor + "/default";
+ bool declared = AServiceManager_isDeclared(instance.c_str());
+ if (!declared) {
+ return nullptr;
+ }
+ ndk::SpAIBinder memtrack_binder =
+ ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str()));
+ return V1_aidl::IMemtrack::fromBinder(memtrack_binder);
+}
+
+bool MemtrackProxy::CheckUid(uid_t calling_uid) {
+ // Allow AID_SHELL for adb shell dumpsys meminfo
+ return calling_uid == AID_SYSTEM || calling_uid == AID_ROOT || calling_uid == AID_SHELL;
+}
+
+bool MemtrackProxy::CheckPid(pid_t calling_pid, pid_t request_pid) {
+ return calling_pid == request_pid;
+}
+
+MemtrackProxy::MemtrackProxy()
+ : memtrack_hidl_instance_(MemtrackProxy::MemtrackHidlInstance()),
+ memtrack_aidl_instance_(MemtrackProxy::MemtrackAidlInstance()) {}
+
+ndk::ScopedAStatus MemtrackProxy::getMemory(int pid, MemtrackType type,
+ std::vector<MemtrackRecord>* _aidl_return) {
+ if (pid < 0) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (!MemtrackProxy::CheckPid(AIBinder_getCallingPid(), pid) &&
+ !MemtrackProxy::CheckUid(AIBinder_getCallingUid())) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_SECURITY,
+ "Only AID_ROOT, AID_SYSTEM and AID_SHELL can request getMemory() for PIDs other "
+ "than the calling PID");
+ }
+
+ if (type != MemtrackType::OTHER && type != MemtrackType::GL && type != MemtrackType::GRAPHICS &&
+ type != MemtrackType::MULTIMEDIA && type != MemtrackType::CAMERA) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ _aidl_return->clear();
+
+ if (memtrack_aidl_instance_) {
+ return memtrack_aidl_instance_->getMemory(pid, type, _aidl_return);
+ } else if (memtrack_hidl_instance_) {
+ ndk::ScopedAStatus aidl_status;
+
+ Return<void> ret = memtrack_hidl_instance_->getMemory(
+ pid, static_cast<V1_0_hidl::MemtrackType>(type),
+ [&_aidl_return, &aidl_status](V1_0_hidl::MemtrackStatus status,
+ hidl_vec<V1_0_hidl::MemtrackRecord> records) {
+ switch (status) {
+ case V1_0_hidl::MemtrackStatus::SUCCESS:
+ aidl_status = ndk::ScopedAStatus::ok();
+ break;
+ case V1_0_hidl::MemtrackStatus::MEMORY_TRACKING_NOT_SUPPORTED:
+ [[fallthrough]];
+ case V1_0_hidl::MemtrackStatus::TYPE_NOT_SUPPORTED:
+ [[fallthrough]];
+ default:
+ aidl_status =
+ ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ return;
+ }
+
+ _aidl_return->resize(records.size());
+ for (size_t i = 0; i < records.size(); i++) {
+ if (!translate(records[i], &(*_aidl_return)[i])) {
+ aidl_status = ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_SERVICE_SPECIFIC,
+ "Failed to convert HIDL MemtrackRecord to AIDL");
+ return;
+ }
+ }
+ });
+
+ // Check HIDL return
+ if (!ret.isOk()) {
+ const char* err_msg = "HIDL Memtrack::getMemory() failed";
+ aidl_status =
+ ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC, err_msg);
+ LOG(ERROR) << err_msg << ": " << ret.description();
+ }
+
+ return aidl_status;
+ }
+
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER,
+ "Memtrack HAL service not available");
+}
+
+ndk::ScopedAStatus MemtrackProxy::getGpuDeviceInfo(std::vector<DeviceInfo>* _aidl_return) {
+ if (!MemtrackProxy::CheckUid(AIBinder_getCallingUid())) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_SECURITY,
+ "Only AID_ROOT, AID_SYSTEM and AID_SHELL can request getGpuDeviceInfo()");
+ }
+
+ _aidl_return->clear();
+
+ if (memtrack_aidl_instance_ ||
+ (memtrack_aidl_instance_ = MemtrackProxy::MemtrackAidlInstance())) {
+ return memtrack_aidl_instance_->getGpuDeviceInfo(_aidl_return);
+ }
+
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER,
+ "Memtrack HAL service not available");
+}
+
+} // namespace memtrack
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/services/memtrackproxy/include/memtrackproxy/MemtrackProxy.h b/services/memtrackproxy/include/memtrackproxy/MemtrackProxy.h
new file mode 100644
index 0000000..5ac1fbf
--- /dev/null
+++ b/services/memtrackproxy/include/memtrackproxy/MemtrackProxy.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/memtrack/BnMemtrack.h>
+#include <aidl/android/hardware/memtrack/DeviceInfo.h>
+#include <aidl/android/hardware/memtrack/IMemtrack.h>
+#include <aidl/android/hardware/memtrack/MemtrackRecord.h>
+#include <aidl/android/hardware/memtrack/MemtrackType.h>
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+
+using ::android::sp;
+
+namespace V1_0_hidl = ::android::hardware::memtrack::V1_0;
+namespace V1_aidl = ::aidl::android::hardware::memtrack;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace memtrack {
+
+__attribute__((warn_unused_result)) bool translate(const V1_0_hidl::MemtrackRecord& in,
+ V1_aidl::MemtrackRecord* out);
+
+class MemtrackProxy : public BnMemtrack {
+public:
+ MemtrackProxy();
+ ndk::ScopedAStatus getMemory(int pid, MemtrackType type,
+ std::vector<MemtrackRecord>* _aidl_return) override;
+ ndk::ScopedAStatus getGpuDeviceInfo(std::vector<DeviceInfo>* _aidl_return) override;
+
+private:
+ static sp<V1_0_hidl::IMemtrack> MemtrackHidlInstance();
+ static std::shared_ptr<V1_aidl::IMemtrack> MemtrackAidlInstance();
+ static bool CheckUid(uid_t calling_uid);
+ static bool CheckPid(pid_t calling_pid, pid_t request_pid);
+
+ sp<V1_0_hidl::IMemtrack> memtrack_hidl_instance_;
+ std::shared_ptr<V1_aidl::IMemtrack> memtrack_aidl_instance_;
+};
+
+} // namespace memtrack
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/services/memtrackproxy/test/Android.bp b/services/memtrackproxy/test/Android.bp
new file mode 100644
index 0000000..f943761
--- /dev/null
+++ b/services/memtrackproxy/test/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "memtrackproxy_test",
+ srcs: [
+ "MemtrackProxyTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libmemtrackproxy",
+ "android.hardware.memtrack-V1-ndk_platform",
+ ],
+ test_suites: ["general-tests"],
+ require_root: true,
+}
diff --git a/services/memtrackproxy/test/MemtrackProxyTest.cpp b/services/memtrackproxy/test/MemtrackProxyTest.cpp
new file mode 100644
index 0000000..16dfba0
--- /dev/null
+++ b/services/memtrackproxy/test/MemtrackProxyTest.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/hardware/memtrack/DeviceInfo.h>
+#include <aidl/android/hardware/memtrack/IMemtrack.h>
+#include <aidl/android/hardware/memtrack/MemtrackRecord.h>
+#include <aidl/android/hardware/memtrack/MemtrackType.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+using aidl::android::hardware::memtrack::DeviceInfo;
+using aidl::android::hardware::memtrack::IMemtrack;
+using aidl::android::hardware::memtrack::MemtrackRecord;
+using aidl::android::hardware::memtrack::MemtrackType;
+
+class MemtrackProxyTest : public ::testing::Test {
+public:
+ virtual void SetUp() override {
+ const char* kMemtrackProxyService = "memtrack.proxy";
+ auto memtrackProxyBinder =
+ ndk::SpAIBinder(AServiceManager_waitForService(kMemtrackProxyService));
+ memtrack_proxy_ = IMemtrack::fromBinder(memtrackProxyBinder);
+ ASSERT_NE(memtrack_proxy_, nullptr);
+ }
+
+ std::shared_ptr<IMemtrack> memtrack_proxy_;
+};
+
+TEST_F(MemtrackProxyTest, GetMemoryForInvalidPid) {
+ int pid = -1;
+
+ for (MemtrackType type : ndk::enum_range<MemtrackType>()) {
+ std::vector<MemtrackRecord> records;
+
+ auto status = memtrack_proxy_->getMemory(pid, type, &records);
+
+ EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ }
+}
+
+TEST_F(MemtrackProxyTest, GetMemoryForCallingPid) {
+ int pid = getpid();
+
+ for (MemtrackType type : ndk::enum_range<MemtrackType>()) {
+ std::vector<MemtrackRecord> records;
+
+ auto status = memtrack_proxy_->getMemory(pid, type, &records);
+
+ EXPECT_TRUE(status.isOk());
+ }
+}
+
+TEST_F(MemtrackProxyTest, GetMemoryForOtherPid) {
+ int pid = 1;
+
+ for (MemtrackType type : ndk::enum_range<MemtrackType>()) {
+ std::vector<MemtrackRecord> records;
+
+ auto status = memtrack_proxy_->getMemory(pid, type, &records);
+
+ // Test is run as root
+ EXPECT_TRUE(status.isOk());
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index ca9ff7c..4151b45 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -7,9 +7,6 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-subdirs = [
- "hidl"
-]
cc_library_shared {
name: "libsensorservice",
@@ -52,9 +49,12 @@
"libhardware_legacy",
"libutils",
"liblog",
+ "libactivitymanager_aidl",
+ "libbatterystats_aidl",
"libbinder",
"libsensor",
"libsensorprivacy",
+ "libpermission",
"libprotoutil",
"libcrypto",
"libbase",
@@ -71,8 +71,12 @@
generated_headers: ["framework-cppstream-protos"],
- // our public headers depend on libsensor and libsensorprivacy
- export_shared_lib_headers: ["libsensor", "libsensorprivacy"],
+ export_shared_lib_headers: [
+ "libactivitymanager_aidl",
+ "libsensor",
+ "libsensorprivacy",
+ "libpermission",
+ ],
}
cc_binary {
diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h
index 43a750c..09eb2c1 100644
--- a/services/sensorservice/BatteryService.h
+++ b/services/sensorservice/BatteryService.h
@@ -17,7 +17,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <binder/IBatteryStats.h>
+#include <batterystats/IBatteryStats.h>
#include <utils/Singleton.h>
namespace android {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 3455320..082356d 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -211,8 +211,8 @@
layer.frameNumber = mCurrentFrameNumber;
layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+ const bool useFiltering =
+ targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -847,6 +847,36 @@
}
}
+bool BufferLayer::bufferNeedsFiltering() const {
+ // Layers that don't resize along with their buffer, don't need filtering.
+ if (!isFixedSize()) {
+ return false;
+ }
+
+ if (!mBufferInfo.mBuffer) {
+ return false;
+ }
+
+ uint32_t bufferWidth = mBufferInfo.mBuffer->width;
+ uint32_t bufferHeight = mBufferInfo.mBuffer->height;
+
+ // Undo any transformations on the buffer and return the result.
+ const State& s(getDrawingState());
+ if (s.transform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+
+ if (s.transformToDisplayInverse) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
+ }
+ }
+
+ const Rect layerSize{getBounds()};
+ return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 26bfb49..c7e8ad7 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -118,6 +118,10 @@
ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
+ // Returns true if the transformed buffer size does not match the layer size and we need
+ // to apply filtering.
+ bool bufferNeedsFiltering() const;
+
// -----------------------------------------------------------------------
// Functions that must be implemented by derived classes
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 790f2ec..41dd7bf 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -760,6 +760,7 @@
static_cast<float>(s.active.transform.ty() + s.active.h)),
radius);
}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 866007e..eb24a22 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -108,6 +108,7 @@
cc_binary {
name: "vr_hwc",
+ enabled: false,
system_ext_specific: true,
vintf_fragments: ["manifest_vr_hwc.xml"],
srcs: [
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 4b69bec..2913850 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1088,7 +1088,8 @@
ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)",
strerror(-err), err);
- err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1);
+ err =
+ window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, nsecs_t{-1});
if (err != android::OK) {
ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)",
strerror(-err), err);
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index a513239..438e5dd 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -842,6 +842,8 @@
bool ret = true;
switch (device->properties.apiVersion ^
VK_VERSION_PATCH(device->properties.apiVersion)) {
+ case VK_API_VERSION_1_2:
+ FALLTHROUGH_INTENDED;
case VK_API_VERSION_1_1:
ret &=
visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
@@ -896,6 +898,8 @@
inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) {
bool ret = true;
switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
+ case VK_API_VERSION_1_2:
+ FALLTHROUGH_INTENDED;
case VK_API_VERSION_1_1:
ret &= visitor->Visit("deviceGroups", &instance->device_groups);
FALLTHROUGH_INTENDED;
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 73586d4..c3f4963 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -433,6 +433,10 @@
VkJsonDeviceGroup device_group;
std::vector<VkPhysicalDeviceGroupProperties> group_properties;
group_properties.resize(count);
+ for (auto& properties : group_properties) {
+ properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
+ properties.pNext = nullptr;
+ }
result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count,
group_properties.data());
if (result != VK_SUCCESS) {