[automerger skipped] DO NOT MERGE: SurfaceFlinger: Add Transaction#sanitize am: 1ff38ab351 am: 5882fa4ab0 -s ours am: 3073c42ed2 -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/16811474
Change-Id: Ia19d527b6a2279bd09aa47a16fbda897fb3bd6ca
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 8bcb1e5..7ef26bf 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,10 +1,12 @@
[Builtin Hooks]
+bpfmt = true
clang_format = true
[Builtin Hooks Options]
# 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/installd/
cmds/servicemanager/
include/input/
include/powermanager/
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4b64203..260ee8d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -67,5 +67,66 @@
}
]
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "SurfaceFlinger_test",
+ "options": [
+ {
+ "include-filter": "*CredentialsTest.*"
+ },
+ {
+ "include-filter": "*SurfaceFlingerStress.*"
+ },
+ {
+ "include-filter": "*SurfaceInterceptorTest.*"
+ },
+ {
+ "include-filter": "*LayerTransactionTest.*"
+ },
+ {
+ "include-filter": "*LayerTypeTransactionTest.*"
+ },
+ {
+ "include-filter": "*LayerUpdateTest.*"
+ },
+ {
+ "include-filter": "*GeometryLatchingTest.*"
+ },
+ {
+ "include-filter": "*CropLatchingTest.*"
+ },
+ {
+ "include-filter": "*ChildLayerTest.*"
+ },
+ {
+ "include-filter": "*ScreenCaptureTest.*"
+ },
+ {
+ "include-filter": "*ScreenCaptureChildOnlyTest.*"
+ },
+ {
+ "include-filter": "*DereferenceSurfaceControlTest.*"
+ },
+ {
+ "include-filter": "*BoundlessLayerTest.*"
+ },
+ {
+ "include-filter": "*MultiDisplayLayerBoundsTest.*"
+ },
+ {
+ "include-filter": "*InvalidHandleTest.*"
+ },
+ {
+ "include-filter": "*VirtualDisplayTest.*"
+ },
+ {
+ "include-filter": "*RelativeZTest.*"
+ },
+ {
+ "include-filter": "*RefreshRateOverlayTest.*"
+ }
+ ]
+ }
]
}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 783a475..9bd733d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -239,13 +239,13 @@
} },
{ "memory", "Memory", 0, {
{ OPT, "events/mm_event/mm_event_record/enable" },
- { OPT, "events/kmem/rss_stat/enable" },
+ { OPT, "events/synthetic/rss_stat_throttled/enable" },
{ OPT, "events/kmem/ion_heap_grow/enable" },
{ OPT, "events/kmem/ion_heap_shrink/enable" },
{ OPT, "events/ion/ion_stat/enable" },
{ OPT, "events/gpu_mem/gpu_mem_total/enable" },
} },
- { "thermal", "Thermal event", 0, {
+ { "thermal", "Thermal event", ATRACE_TAG_THERMAL, {
{ REQ, "events/thermal/thermal_temperature/enable" },
{ OPT, "events/thermal/cdev_update/enable" },
} },
@@ -1224,10 +1224,7 @@
if (ret < 0) {
for (int i = optind; i < argc; i++) {
- if (!setCategoryEnable(argv[i])) {
- fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
- exit(1);
- }
+ setCategoryEnable(argv[i]);
}
break;
}
@@ -1343,10 +1340,10 @@
// contain entries from only one CPU can cause "begin" entries without a
// matching "end" entry to show up if a task gets migrated from one CPU to
// another.
- if (!onlyUserspace)
+ if (!onlyUserspace) {
ok = clearTrace();
-
- writeClockSyncMarker();
+ writeClockSyncMarker();
+ }
if (ok && !async && !traceStream) {
// Sleep to allow the trace to be captured.
struct timespec timeLeft;
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 01c4723..1c3a4f2 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -35,6 +35,8 @@
chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable
chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_exit/enable
chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_free/enable
+ chmod 0666 /sys/kernel/tracing/events/sched/sched_process_free/enable
chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable
chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable
chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/enable
@@ -282,6 +284,21 @@
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu23/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu23/trace
+# Setup synthetic events
+ chmod 0666 /sys/kernel/tracing/synthetic_events
+ chmod 0666 /sys/kernel/debug/tracing/synthetic_events
+
+ # rss_stat_throttled
+ write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+ write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+
+# Set up histogram triggers
+ # rss_stat_throttled (bucket size == 512KB)
+ chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+ chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
+ write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+ write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
# will likely fail with EBUSY as it would be in use by traced_probes.
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index c900a24..c3d2601 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -49,6 +49,7 @@
"liblog",
"libselinux",
"libbinder",
+ "packagemanager_aidl-cpp",
],
cflags: [
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index be2c702..8f1c01a 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -52,7 +52,7 @@
}
struct SecurityContext_Delete {
- void operator()(security_context_t p) const {
+ void operator()(char* p) const {
freecon(p);
}
};
@@ -108,7 +108,7 @@
}
if (is_selinux_enabled() && seLinuxContext.size() > 0) {
String8 seLinuxContext8(seLinuxContext);
- security_context_t tmp = nullptr;
+ char* tmp = nullptr;
getfilecon(fullPath.string(), &tmp);
Unique_SecurityContext context(tmp);
if (checkWrite) {
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
new file mode 100644
index 0000000..a65f6de
--- /dev/null
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * 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_cmds_cmd_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+cc_fuzz {
+ name: "cmd_fuzzer",
+ srcs: [
+ "cmd_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libcmd",
+ "liblog",
+ "libselinux",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/cmds/cmd/fuzzer/README.md b/cmds/cmd/fuzzer/README.md
new file mode 100644
index 0000000..db37ece
--- /dev/null
+++ b/cmds/cmd/fuzzer/README.md
@@ -0,0 +1,51 @@
+# Fuzzer for libcmd_fuzzer
+
+## Plugin Design Considerations
+The fuzzer plugin for libcmd is designed based on the understanding of the library and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+libcmd supports the following parameters:
+1. In (parameter name: `in`)
+2. Out (parameter name: `out`)
+3. Err (parameter name: `err`)
+4. Run Mode (parameter name: `runMode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `in` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `out` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `err` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `runMode` | 1.`RunMode::kStandalone` 2. `RunMode::kLibrary` | Value chosen from valid values using FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the cmd module.
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build cmd_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) cmd_fuzzer
+```
+#### Steps to run
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/cmd_fuzzer/cmd_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/cmds/cmd/fuzzer/cmd_fuzzer.cpp b/cmds/cmd/fuzzer/cmd_fuzzer.cpp
new file mode 100644
index 0000000..ab514a1
--- /dev/null
+++ b/cmds/cmd/fuzzer/cmd_fuzzer.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 <binder/TextOutput.h>
+#include <cmd.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+using namespace std;
+using namespace android;
+
+class TestTextOutput : public TextOutput {
+public:
+ TestTextOutput() {}
+ virtual ~TestTextOutput() {}
+
+ virtual status_t print(const char* /*txt*/, size_t /*len*/) { return NO_ERROR; }
+ virtual void moveIndent(int /*delta*/) { return; }
+ virtual void pushBundle() { return; }
+ virtual void popBundle() { return; }
+};
+
+class CmdFuzzer {
+public:
+ void process(const uint8_t* data, size_t size);
+
+private:
+ FuzzedDataProvider* mFDP = nullptr;
+};
+
+void CmdFuzzer::process(const uint8_t* data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ vector<string> arguments;
+ if (mFDP->ConsumeBool()) {
+ if (mFDP->ConsumeBool()) {
+ arguments = {"-w", "media.aaudio"};
+ } else {
+ arguments = {"-l"};
+ }
+ } else {
+ while (mFDP->remaining_bytes() > 0) {
+ size_t sizestr = mFDP->ConsumeIntegralInRange<size_t>(1, mFDP->remaining_bytes());
+ string argument = mFDP->ConsumeBytesAsString(sizestr);
+ arguments.emplace_back(argument);
+ }
+ }
+ vector<string_view> argSV;
+ for (auto& argument : arguments) {
+ argSV.emplace_back(argument.c_str());
+ }
+ int32_t in = open("/dev/null", O_RDWR | O_CREAT);
+ int32_t out = open("/dev/null", O_RDWR | O_CREAT);
+ int32_t err = open("/dev/null", O_RDWR | O_CREAT);
+ TestTextOutput output;
+ TestTextOutput error;
+ RunMode runMode = mFDP->ConsumeBool() ? RunMode::kStandalone : RunMode::kLibrary;
+ cmdMain(argSV, output, error, in, out, err, runMode);
+ delete mFDP;
+ close(in);
+ close(out);
+ close(err);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ CmdFuzzer cmdFuzzer;
+ cmdFuzzer.process(data, size);
+ return 0;
+}
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index aff32c3..a2491e5 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -86,9 +86,11 @@
shared_libs: [
"android.hardware.dumpstate@1.0",
"android.hardware.dumpstate@1.1",
+ "android.hardware.dumpstate-V1-ndk",
"libziparchive",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcrypto",
"libcutils",
"libdebuggerd_client",
@@ -100,6 +102,7 @@
"liblog",
"libutils",
"libbinderdebug",
+ "packagemanager_aidl-cpp",
],
srcs: [
"DumpstateService.cpp",
@@ -173,7 +176,6 @@
test_suites: ["device-tests"],
}
-
// =======================#
// dumpstate_test_fixture #
// =======================#
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
index c2c8a72..4d3a67b 100644
--- a/cmds/dumpstate/DumpPool.cpp
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -33,6 +33,20 @@
const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
+
+void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd) {
+ DurationReporter duration_reporter("Wait for " + title, true);
+
+ std::string result = future.get();
+ if (result.empty()) {
+ return;
+ }
+ DumpFileToFd(out_fd, title, result);
+ if (unlink(result.c_str())) {
+ MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+ }
+}
+
DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false),
log_duration_(true) {
assert(!tmp_root.empty());
@@ -40,31 +54,10 @@
}
DumpPool::~DumpPool() {
- shutdown();
-}
-
-void DumpPool::start(int thread_counts) {
- assert(thread_counts > 0);
- assert(threads_.empty());
- if (thread_counts > MAX_THREAD_COUNT) {
- thread_counts = MAX_THREAD_COUNT;
- }
- MYLOGI("Start thread pool:%d", thread_counts);
- shutdown_ = false;
- for (int i = 0; i < thread_counts; i++) {
- threads_.emplace_back(std::thread([=]() {
- setThreadName(pthread_self(), i + 1);
- loop();
- }));
- }
-}
-
-void DumpPool::shutdown() {
std::unique_lock lock(lock_);
if (shutdown_ || threads_.empty()) {
return;
}
- futures_map_.clear();
while (!tasks_.empty()) tasks_.pop();
shutdown_ = true;
@@ -76,27 +69,22 @@
}
threads_.clear();
deleteTempFiles(tmp_root_);
- MYLOGI("shutdown thread pool");
+ MYLOGI("shutdown thread pool\n");
}
-void DumpPool::waitForTask(const std::string& task_name, const std::string& title,
- int out_fd) {
- DurationReporter duration_reporter("Wait for " + task_name, true);
- auto iterator = futures_map_.find(task_name);
- if (iterator == futures_map_.end()) {
- MYLOGW("Task %s does not exist", task_name.c_str());
- return;
+void DumpPool::start(int thread_counts) {
+ assert(thread_counts > 0);
+ assert(threads_.empty());
+ if (thread_counts > MAX_THREAD_COUNT) {
+ thread_counts = MAX_THREAD_COUNT;
}
- Future future = iterator->second;
- futures_map_.erase(iterator);
-
- std::string result = future.get();
- if (result.empty()) {
- return;
- }
- DumpFileToFd(out_fd, title, result);
- if (unlink(result.c_str())) {
- MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+ MYLOGI("Start thread pool:%d\n", thread_counts);
+ shutdown_ = false;
+ for (int i = 0; i < thread_counts; i++) {
+ threads_.emplace_back(std::thread([=]() {
+ setThreadName(pthread_self(), i + 1);
+ loop();
+ }));
}
}
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
index 0c3c2cc..9fb0fcc 100644
--- a/cmds/dumpstate/DumpPool.h
+++ b/cmds/dumpstate/DumpPool.h
@@ -18,7 +18,6 @@
#define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
#include <future>
-#include <map>
#include <queue>
#include <string>
@@ -32,8 +31,26 @@
class DumpPoolTest;
/*
+ * Waits until the task is finished. Dumps the task results to the specified
+ * out_fd.
+ *
+ * |future| The task future.
+ * |title| Dump title string to the out_fd, an empty string for nothing.
+ * |out_fd| The target file to dump the result from the task.
+ */
+void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd);
+
+/*
+ * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
+ */
+
+inline void WaitForTask(std::future<std::string> future) {
+ WaitForTask(std::move(future), "", STDOUT_FILENO);
+}
+
+/*
* A thread pool with the fixed number of threads to execute multiple dump tasks
- * simultaneously for the dumpstate. The dump task is a callable function. It
+ * simultaneously for dumpstate. The dump task is a callable function. It
* could include a file descriptor as a parameter to redirect dump results, if
* it needs to output results to the bugreport. This can avoid messing up
* bugreport's results when multiple dump tasks are running at the same time.
@@ -44,13 +61,16 @@
* }
* ...
* DumpPool pool(tmp_root);
- * pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
+ * auto task = pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
* ...
- * pool.waitForTask("TaskName");
+ * WaitForTask(task);
*
* DumpFoo is a callable function included a out_fd parameter. Using the
* enqueueTaskWithFd method in DumpPool to enqueue the task to the pool. The
* std::placeholders::_1 is a placeholder for DumpPool to pass a fd argument.
+ *
+ * std::futures returned by `enqueueTask*()` must all have their `get` methods
+ * called, or have been destroyed before the DumpPool itself is destroyed.
*/
class DumpPool {
friend class android::os::dumpstate::DumpPoolTest;
@@ -63,6 +83,12 @@
* files.
*/
explicit DumpPool(const std::string& tmp_root);
+
+ /*
+ * Will waits until all threads exit the loop. Destroying DumpPool before destroying the
+ * associated std::futures created by `enqueueTask*` will cause an abort on Android because
+ * Android is built with `-fno-exceptions`.
+ */
~DumpPool();
/*
@@ -73,68 +99,47 @@
void start(int thread_counts = MAX_THREAD_COUNT);
/*
- * Requests to shutdown the pool and waits until all threads exit the loop.
- */
- void shutdown();
-
- /*
* Adds a task into the queue of the thread pool.
*
- * |task_name| The name of the task. It's also the title of the
+ * |duration_title| The name of the task. It's also the title of the
* DurationReporter log.
* |f| Callable function to execute the task.
* |args| A list of arguments.
*
* TODO(b/164369078): remove this api to have just one enqueueTask for consistency.
*/
- template<class F, class... Args> void enqueueTask(const std::string& task_name, F&& f,
- Args&&... args) {
+ template<class F, class... Args>
+ std::future<std::string> enqueueTask(const std::string& duration_title, F&& f, Args&&... args) {
std::function<void(void)> func = std::bind(std::forward<F>(f),
std::forward<Args>(args)...);
- futures_map_[task_name] = post(task_name, func);
+ auto future = post(duration_title, func);
if (threads_.empty()) {
start();
}
+ return future;
}
/*
* Adds a task into the queue of the thread pool. The task takes a file
* descriptor as a parameter to redirect dump results to a temporary file.
*
- * |task_name| The name of the task. It's also the title of the
- * DurationReporter log.
+ * |duration_title| The title of the DurationReporter log.
* |f| Callable function to execute the task.
* |args| A list of arguments. A placeholder std::placeholders::_1 as a fd
* argument needs to be included here.
*/
- template<class F, class... Args> void enqueueTaskWithFd(const std::string& task_name, F&& f,
- Args&&... args) {
+ template<class F, class... Args> std::future<std::string> enqueueTaskWithFd(
+ const std::string& duration_title, F&& f, Args&&... args) {
std::function<void(int)> func = std::bind(std::forward<F>(f),
std::forward<Args>(args)...);
- futures_map_[task_name] = post(task_name, func);
+ auto future = post(duration_title, func);
if (threads_.empty()) {
start();
}
+ return future;
}
/*
- * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
- */
- void waitForTask(const std::string& task_name) {
- waitForTask(task_name, "", STDOUT_FILENO);
- }
-
- /*
- * Waits until the task is finished. Dumps the task results to the specified
- * out_fd.
- *
- * |task_name| The name of the task.
- * |title| Dump title string to the out_fd, an empty string for nothing.
- * |out_fd| The target file to dump the result from the task.
- */
- void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
-
- /*
* Deletes temporary files created by DumpPool.
*/
void deleteTempFiles();
@@ -143,22 +148,22 @@
private:
using Task = std::packaged_task<std::string()>;
- using Future = std::shared_future<std::string>;
template<class T> void invokeTask(T dump_func, const std::string& duration_title, int out_fd);
- template<class T> Future post(const std::string& task_name, T dump_func) {
+ template<class T>
+ std::future<std::string> post(const std::string& duration_title, T dump_func) {
Task packaged_task([=]() {
std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
if (!tmp_file_ptr) {
return std::string("");
}
- invokeTask(dump_func, task_name, tmp_file_ptr->fd.get());
+ invokeTask(dump_func, duration_title, tmp_file_ptr->fd.get());
fsync(tmp_file_ptr->fd.get());
return std::string(tmp_file_ptr->path);
});
std::unique_lock lock(lock_);
- auto future = packaged_task.get_future().share();
+ auto future = packaged_task.get_future();
tasks_.push(std::move(packaged_task));
condition_variable_.notify_one();
return future;
@@ -194,7 +199,6 @@
std::vector<std::thread> threads_;
std::queue<Task> tasks_;
- std::map<std::string, Future> futures_map_;
DISALLOW_COPY_AND_ASSIGN(DumpPool);
};
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index ba25a5a..e42ee05 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -192,7 +192,7 @@
dprintf(fd, "progress:\n");
ds_->progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
- dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str());
+ dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode_string.c_str());
dprintf(fd, "version: %s\n", ds_->version_.c_str());
dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
@@ -202,7 +202,6 @@
dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
dprintf(fd, "name: %s\n", ds_->name_.c_str());
dprintf(fd, "now: %ld\n", ds_->now_);
- dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index c833d0e..aa42541 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -48,11 +48,26 @@
sigemptyset(&child_mask);
sigaddset(&child_mask, SIGCHLD);
+ // block SIGCHLD before we check if a process has exited
if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
printf("*** sigprocmask failed: %s\n", strerror(errno));
return false;
}
+ // if the child has exited already, handle and reset signals before leaving
+ pid_t child_pid = waitpid(pid, status, WNOHANG);
+ if (child_pid != pid) {
+ if (child_pid > 0) {
+ printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
+ sigprocmask(SIG_SETMASK, &old_mask, nullptr);
+ return false;
+ }
+ } else {
+ sigprocmask(SIG_SETMASK, &old_mask, nullptr);
+ return true;
+ }
+
+ // wait for a SIGCHLD
timespec ts;
ts.tv_sec = MSEC_TO_SEC(timeout_ms);
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
@@ -76,7 +91,7 @@
return false;
}
- pid_t child_pid = waitpid(pid, status, WNOHANG);
+ child_pid = waitpid(pid, status, WNOHANG);
if (child_pid != pid) {
if (child_pid != -1) {
printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
@@ -232,7 +247,6 @@
dprintf(out_fd, "*** Error dumping %s (%s): %s\n", path.c_str(), title.c_str(),
strerror(err));
}
- fsync(out_fd);
return -1;
}
return DumpFileFromFdToFd(title, path, fd.get(), out_fd, PropertiesHelper::IsDryRun());
@@ -280,7 +294,6 @@
if (!title.empty()) {
dprintf(fd, "------ %s (%s) ------\n", title.c_str(), command);
- fsync(fd);
}
const std::string& logging_message = options.LoggingMessage();
@@ -299,14 +312,13 @@
// There is no title, but we should still print a dry-run message
dprintf(fd, "%s: skipped on dry run\n", command_string.c_str());
}
- fsync(fd);
return 0;
}
const char* path = args[0];
uint64_t start = Nanotime();
- pid_t pid = fork();
+ pid_t pid = vfork();
/* handle error case */
if (pid < 0) {
@@ -323,7 +335,7 @@
strerror(errno));
}
MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
- return -1;
+ _exit(EXIT_FAILURE);
}
if (options.ShouldCloseAllFileDescriptorsOnExec()) {
@@ -376,7 +388,6 @@
/* handle parent case */
int status;
bool ret = waitpid_with_timeout(pid, options.TimeoutInMs(), &status);
- fsync(fd);
uint64_t elapsed = Nanotime() - start;
if (!ret) {
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 30ef4b9..890c15f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -57,12 +57,15 @@
#include <utility>
#include <vector>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
@@ -89,11 +92,10 @@
#include "DumpstateService.h"
#include "dumpstate.h"
-using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
-using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
-using ::android::hardware::dumpstate::V1_1::DumpstateMode;
-using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
-using ::android::hardware::dumpstate::V1_1::toString;
+namespace dumpstate_hal_hidl_1_0 = android::hardware::dumpstate::V1_0;
+namespace dumpstate_hal_hidl = android::hardware::dumpstate::V1_1;
+namespace dumpstate_hal_aidl = aidl::android::hardware::dumpstate;
+
using ::std::literals::chrono_literals::operator""ms;
using ::std::literals::chrono_literals::operator""s;
using ::std::placeholders::_1;
@@ -118,6 +120,7 @@
using android::os::dumpstate::DumpPool;
using android::os::dumpstate::PropertiesHelper;
using android::os::dumpstate::TaskQueue;
+using android::os::dumpstate::WaitForTask;
// Keep in sync with
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -216,9 +219,9 @@
RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__); \
RETURN_IF_USER_DENIED_CONSENT();
-#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \
+#define WAIT_TASK_WITH_CONSENT_CHECK(future) \
RETURN_IF_USER_DENIED_CONSENT(); \
- pool_ptr->waitForTask(task_name); \
+ WaitForTask(future); \
RETURN_IF_USER_DENIED_CONSENT();
static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
@@ -369,14 +372,10 @@
/*
* Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
* The returned vector is sorted by the mtimes of the dumps with descending
- * order. If |limit_by_mtime| is set, the vector only contains files that
- * were written in the last 30 minutes.
+ * order.
*/
static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
- const std::string& file_prefix,
- bool limit_by_mtime) {
- const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
-
+ const std::string& file_prefix) {
std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
if (dump_dir == nullptr) {
@@ -410,11 +409,6 @@
continue;
}
- if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
- MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
- continue;
- }
-
dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
}
if (!dump_data.empty()) {
@@ -445,7 +439,7 @@
strerror(errno));
}
- if (ds.IsZipping() && add_to_zip) {
+ if (add_to_zip) {
if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
}
@@ -484,7 +478,6 @@
}
void add_mountinfo() {
- if (!ds.IsZipping()) return;
std::string title = "MOUNT INFO";
mount_points.clear();
DurationReporter duration_reporter(title, true);
@@ -807,7 +800,7 @@
printf("Bugreport format version: %s\n", version_.c_str());
printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
- options_->args.c_str(), options_->bugreport_mode.c_str());
+ options_->args.c_str(), options_->bugreport_mode_string.c_str());
printf("\n");
}
@@ -821,11 +814,6 @@
status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
std::chrono::milliseconds timeout = 0ms) {
- if (!IsZipping()) {
- MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
- entry_name.c_str());
- return INVALID_OPERATION;
- }
std::string valid_name = entry_name;
// Rename extension if necessary.
@@ -926,21 +914,12 @@
}
void Dumpstate::AddDir(const std::string& dir, bool recursive) {
- if (!IsZipping()) {
- MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
- return;
- }
MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
DurationReporter duration_reporter(dir, true);
dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
}
bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
- if (!IsZipping()) {
- MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
- entry_name.c_str());
- return false;
- }
MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
if (err != 0) {
@@ -1033,10 +1012,6 @@
}
static void DumpIncidentReport() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
- return;
- }
const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
@@ -1062,10 +1037,6 @@
// This function copies into the .zip the system trace that was snapshotted
// by the early call to MaybeSnapshotSystemTrace(), if any background
// tracing was happening.
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping system trace because it's not a zipped bugreport\n");
- return;
- }
if (!ds.has_system_trace_) {
// No background trace was happening at the time dumpstate was invoked.
return;
@@ -1077,10 +1048,6 @@
}
static void DumpVisibleWindowViews() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping visible views because it's not a zipped bugreport\n");
- return;
- }
DurationReporter duration_reporter("VISIBLE WINDOW VIEWS");
const std::string path = ds.bugreport_internal_dir_ + "/tmp_visible_window_views";
auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
@@ -1121,7 +1088,7 @@
RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
}
-static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
+static void AddAnrTraceDir(const std::string& anr_traces_dir) {
MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
anr_traces_dir.c_str());
@@ -1129,13 +1096,9 @@
// (created with mkostemp or similar) that contains dumps taken earlier
// on in the process.
if (dump_traces_path != nullptr) {
- if (add_to_zip) {
- ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
- } else {
- MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
- dump_traces_path);
- ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
- }
+ MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
+ dump_traces_path);
+ ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
const int ret = unlink(dump_traces_path);
if (ret == -1) {
@@ -1146,14 +1109,12 @@
// Add a specific message for the first ANR Dump.
if (ds.anr_data_.size() > 0) {
+ // The "last" ANR will always be present in the body of the main entry.
AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
- "VM TRACES AT LAST ANR", add_to_zip);
+ "VM TRACES AT LAST ANR", false /* add_to_zip */);
- // The "last" ANR will always be included as separate entry in the zip file. In addition,
- // it will be present in the body of the main entry if |add_to_zip| == false.
- //
// Historical ANRs are always included as separate entries in the bugreport zip file.
- AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
+ AddDumps(ds.anr_data_.begin(), ds.anr_data_.end(),
"HISTORICAL ANR", true /* add_to_zip */);
} else {
printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
@@ -1161,11 +1122,9 @@
}
static void AddAnrTraceFiles() {
- const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
-
std::string anr_traces_dir = "/data/anr";
- AddAnrTraceDir(add_to_zip, anr_traces_dir);
+ AddAnrTraceDir(anr_traces_dir);
RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
@@ -1237,22 +1196,29 @@
std::string path(title);
path.append(" - ").append(String8(service).c_str());
size_t bytes_written = 0;
- status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
- if (status == OK) {
- dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
- std::chrono::duration<double> elapsed_seconds;
- if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
- service == String16("meminfo")) {
- // Use a longer timeout for meminfo, since 30s is not always enough.
- status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
- } else {
- status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
+ if (PropertiesHelper::IsDryRun()) {
+ dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+ dumpsys.writeDumpFooter(STDOUT_FILENO, service, std::chrono::milliseconds(1));
+ } else {
+ status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
+ if (status == OK) {
+ dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+ std::chrono::duration<double> elapsed_seconds;
+ if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+ service == String16("meminfo")) {
+ // Use a longer timeout for meminfo, since 30s is not always enough.
+ status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+ /* as_proto = */ false, elapsed_seconds,
+ bytes_written);
+ } else {
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds,
+ bytes_written);
+ }
+ dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
+ bool dump_complete = (status == OK);
+ dumpsys.stopDumpThread(dump_complete);
}
- dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
- bool dump_complete = (status == OK);
- dumpsys.stopDumpThread(dump_complete);
}
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -1294,10 +1260,6 @@
static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
std::chrono::milliseconds timeout,
std::chrono::milliseconds service_timeout) {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
- return Dumpstate::RunStatus::OK;
- }
sp<android::IServiceManager> sm = defaultServiceManager();
Dumpsys dumpsys(sm.get());
Vector<String16> args;
@@ -1316,7 +1278,7 @@
path.append("_HIGH");
}
path.append(kProtoExt);
- status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
+ status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
if (status == OK) {
status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
bool dumpTerminated = (status == OK);
@@ -1377,12 +1339,6 @@
* if it's not running in the parallel task.
*/
static void DumpHals(int out_fd = STDOUT_FILENO) {
- if (!ds.IsZipping()) {
- RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"},
- CommandOptions::WithTimeout(60).AsRootIfAvailable().Build(),
- false, out_fd);
- return;
- }
RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"},
CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
false, out_fd);
@@ -1594,15 +1550,18 @@
DurationReporter duration_reporter("DUMPSTATE");
// Enqueue slow functions into the thread pool, if the parallel run is enabled.
+ std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins;
if (ds.dump_pool_) {
// Pool was shutdown in DumpstateDefaultAfterCritical method in order to
// drop root user. Restarts it with two threads for the parallel run.
ds.dump_pool_->start(/* thread_counts = */2);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
- ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
- ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
+ dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+ dump_incident_report = ds.dump_pool_->enqueueTask(
+ DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+ dump_board = ds.dump_pool_->enqueueTaskWithFd(
+ DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+ dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
}
// Dump various things. Note that anything that takes "long" (i.e. several seconds) should
@@ -1627,7 +1586,6 @@
DumpFile("BUDDYINFO", "/proc/buddyinfo");
DumpExternalFragmentationInfo();
- DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
RunCommand("PROCESSES AND THREADS",
@@ -1637,7 +1595,7 @@
CommandOptions::AS_ROOT);
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
}
@@ -1734,7 +1692,7 @@
ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_board));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
}
@@ -1763,7 +1721,7 @@
ds.AddDir("/data/misc/bluetooth/logs", true);
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_CHECKINS_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_checkins));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
}
@@ -1797,7 +1755,7 @@
dump_frozen_cgroupfs();
if (ds.dump_pool_) {
- WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
+ WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report));
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
DumpIncidentReport);
@@ -1822,6 +1780,7 @@
time_t logcat_ts = time(nullptr);
/* collect stack traces from Dalvik and native processes (needs root) */
+ std::future<std::string> dump_traces;
if (dump_pool_) {
RETURN_IF_USER_DENIED_CONSENT();
// One thread is enough since we only need to enqueue DumpTraces here.
@@ -1829,15 +1788,18 @@
// DumpTraces takes long time, post it to the another thread in the
// pool, if pool is available
- dump_pool_->enqueueTask(DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
+ dump_traces = dump_pool_->enqueueTask(
+ DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
} else {
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
&dump_traces_path);
}
/* Run some operations that require root. */
- ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
- ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+ if (!PropertiesHelper::IsDryRun()) {
+ ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
+ ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
+ }
ds.AddDir(RECOVERY_DIR, true);
ds.AddDir(RECOVERY_DATA_DIR, true);
@@ -1876,12 +1838,11 @@
if (dump_pool_) {
RETURN_IF_USER_DENIED_CONSENT();
- dump_pool_->waitForTask(DUMP_TRACES_TASK);
+ WaitForTask(std::move(dump_traces));
- // Current running thread in the pool is the root user also. Shutdown
- // the pool and restart later to ensure all threads in the pool could
- // drop the root user.
- dump_pool_->shutdown();
+ // Current running thread in the pool is the root user also. Delete
+ // the pool and make a new one later to ensure none of threads in the pool are root.
+ dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
}
if (!DropRootUser()) {
return Dumpstate::RunStatus::ERROR;
@@ -1912,8 +1873,9 @@
} else {
// DumpHals takes long time, post it to the another thread in the pool,
// if pool is available.
+ std::future<std::string> dump_hals;
if (ds.dump_pool_) {
- ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+ dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
}
// Contains various system properties and process startup info.
do_dmesg();
@@ -1923,7 +1885,7 @@
DoKmsg();
// DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
if (ds.dump_pool_) {
- ds.dump_pool_->waitForTask(DUMP_HALS_TASK);
+ WaitForTask(std::move(dump_hals));
} else {
RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
}
@@ -1957,12 +1919,14 @@
// Starts thread pool after the root user is dropped, and two additional threads
// are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
+ std::future<std::string> dump_board;
if (ds.dump_pool_) {
ds.dump_pool_->start(/*thread_counts =*/2);
// DumpstateBoard takes long time, post it to the another thread in the pool,
// if pool is available.
- ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+ dump_board = ds.dump_pool_->enqueueTaskWithFd(
+ DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
}
DumpstateRadioCommon(include_sensitive_info);
@@ -2045,7 +2009,7 @@
printf("========================================================\n");
if (ds.dump_pool_) {
- ds.dump_pool_->waitForTask(DUMP_BOARD_TASK);
+ WaitForTask(std::move(dump_board));
} else {
RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
}
@@ -2190,16 +2154,199 @@
return RunStatus::OK;
}
+static dumpstate_hal_hidl::DumpstateMode GetDumpstateHalModeHidl(
+ const Dumpstate::BugreportMode bugreport_mode) {
+ switch (bugreport_mode) {
+ case Dumpstate::BugreportMode::BUGREPORT_FULL:
+ return dumpstate_hal_hidl::DumpstateMode::FULL;
+ case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+ return dumpstate_hal_hidl::DumpstateMode::INTERACTIVE;
+ case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+ return dumpstate_hal_hidl::DumpstateMode::REMOTE;
+ case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+ return dumpstate_hal_hidl::DumpstateMode::WEAR;
+ case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+ return dumpstate_hal_hidl::DumpstateMode::CONNECTIVITY;
+ case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+ return dumpstate_hal_hidl::DumpstateMode::WIFI;
+ case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+ return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
+ }
+ return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
+}
+
+static dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode GetDumpstateHalModeAidl(
+ const Dumpstate::BugreportMode bugreport_mode) {
+ switch (bugreport_mode) {
+ case Dumpstate::BugreportMode::BUGREPORT_FULL:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::FULL;
+ case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::INTERACTIVE;
+ case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::REMOTE;
+ case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WEAR;
+ case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::CONNECTIVITY;
+ case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WIFI;
+ case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
+ }
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
+}
+
+static void DoDumpstateBoardHidl(
+ const sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_1_0,
+ const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
+ const Dumpstate::BugreportMode bugreport_mode,
+ const size_t timeout_sec) {
+
+ using ScopedNativeHandle =
+ std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
+ ScopedNativeHandle handle(native_handle_create(static_cast<int>(dumpstate_fds.size()), 0),
+ [](native_handle_t* handle) {
+ // we don't close file handle's here
+ // via native_handle_close(handle)
+ // instead we let dumpstate_fds close the file handles when
+ // dumpstate_fds gets destroyed
+ native_handle_delete(handle);
+ });
+ if (handle == nullptr) {
+ MYLOGE("Could not create native_handle for dumpstate HAL\n");
+ return;
+ }
+
+ for (size_t i = 0; i < dumpstate_fds.size(); i++) {
+ handle.get()->data[i] = dumpstate_fds[i].get();
+ }
+
+ // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
+ // implement just 1.0.
+ const char* descriptor_to_kill;
+ using DumpstateBoardTask = std::packaged_task<bool()>;
+ DumpstateBoardTask dumpstate_board_task;
+ sp<dumpstate_hal_hidl::IDumpstateDevice> dumpstate_hal(
+ dumpstate_hal_hidl::IDumpstateDevice::castFrom(dumpstate_hal_1_0));
+ if (dumpstate_hal != nullptr) {
+ MYLOGI("Using IDumpstateDevice v1.1 HIDL HAL");
+
+ dumpstate_hal_hidl::DumpstateMode dumpstate_hal_mode =
+ GetDumpstateHalModeHidl(bugreport_mode);
+
+ descriptor_to_kill = dumpstate_hal_hidl::IDumpstateDevice::descriptor;
+ dumpstate_board_task =
+ DumpstateBoardTask([timeout_sec, dumpstate_hal_mode, dumpstate_hal, &handle]() -> bool {
+ ::android::hardware::Return<dumpstate_hal_hidl::DumpstateStatus> status =
+ dumpstate_hal->dumpstateBoard_1_1(handle.get(), dumpstate_hal_mode,
+ SEC_TO_MSEC(timeout_sec));
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ return false;
+ } else if (status != dumpstate_hal_hidl::DumpstateStatus::OK) {
+ MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n",
+ dumpstate_hal_hidl::toString(status).c_str());
+ return false;
+ }
+ return true;
+ });
+ } else {
+ MYLOGI("Using IDumpstateDevice v1.0 HIDL HAL");
+
+ descriptor_to_kill = dumpstate_hal_hidl_1_0::IDumpstateDevice::descriptor;
+ dumpstate_board_task = DumpstateBoardTask([dumpstate_hal_1_0, &handle]() -> bool {
+ ::android::hardware::Return<void> status =
+ dumpstate_hal_1_0->dumpstateBoard(handle.get());
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ return false;
+ }
+ return true;
+ });
+ }
+ auto result = dumpstate_board_task.get_future();
+ std::thread(std::move(dumpstate_board_task)).detach();
+
+ if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+ MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
+ if (!android::base::SetProperty(
+ "ctl.interface_restart",
+ android::base::StringPrintf("%s/default", descriptor_to_kill))) {
+ MYLOGE("Couldn't restart dumpstate HAL\n");
+ }
+ }
+ // Wait some time for init to kill dumpstate vendor HAL
+ constexpr size_t killing_timeout_sec = 10;
+ if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+ MYLOGE(
+ "killing dumpstateBoard timed out after %zus, continue and "
+ "there might be racing in content\n",
+ killing_timeout_sec);
+ }
+}
+
+static void DoDumpstateBoardAidl(
+ const std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal,
+ const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
+ const Dumpstate::BugreportMode bugreport_mode, const size_t timeout_sec) {
+ MYLOGI("Using IDumpstateDevice AIDL HAL");
+
+ const char* descriptor_to_kill;
+ using DumpstateBoardTask = std::packaged_task<bool()>;
+ DumpstateBoardTask dumpstate_board_task;
+ dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode dumpstate_hal_mode =
+ GetDumpstateHalModeAidl(bugreport_mode);
+
+ descriptor_to_kill = dumpstate_hal_aidl::IDumpstateDevice::descriptor;
+ dumpstate_board_task = DumpstateBoardTask([dumpstate_hal, &dumpstate_fds, dumpstate_hal_mode,
+ timeout_sec]() -> bool {
+ auto status = dumpstate_hal->dumpstateBoard(dumpstate_fds, dumpstate_hal_mode, timeout_sec);
+
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.getDescription().c_str());
+ return false;
+ }
+ return true;
+ });
+ auto result = dumpstate_board_task.get_future();
+ std::thread(std::move(dumpstate_board_task)).detach();
+
+ if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+ MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
+ if (!android::base::SetProperty(
+ "ctl.interface_restart",
+ android::base::StringPrintf("%s/default", descriptor_to_kill))) {
+ MYLOGE("Couldn't restart dumpstate HAL\n");
+ }
+ }
+ // Wait some time for init to kill dumpstate vendor HAL
+ constexpr size_t killing_timeout_sec = 10;
+ if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+ MYLOGE(
+ "killing dumpstateBoard timed out after %zus, continue and "
+ "there might be racing in content\n",
+ killing_timeout_sec);
+ }
+}
+
+static std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> GetDumpstateBoardAidlService() {
+ const std::string aidl_instance_name =
+ std::string(dumpstate_hal_aidl::IDumpstateDevice::descriptor) + "/default";
+
+ if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
+ return nullptr;
+ }
+
+ ndk::SpAIBinder dumpstateBinder(AServiceManager_waitForService(aidl_instance_name.c_str()));
+
+ return dumpstate_hal_aidl::IDumpstateDevice::fromBinder(dumpstateBinder);
+}
+
void Dumpstate::DumpstateBoard(int out_fd) {
dprintf(out_fd, "========================================================\n");
dprintf(out_fd, "== Board\n");
dprintf(out_fd, "========================================================\n");
- if (!IsZipping()) {
- MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
- return;
- }
-
/*
* mount debugfs for non-user builds with ro.product.debugfs_restrictions.enabled
* set to true and unmount it after invoking dumpstateBoard_* methods.
@@ -2211,8 +2358,7 @@
if (mount_debugfs) {
RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
AS_ROOT_20);
- RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"},
- AS_ROOT_20);
+ RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"}, AS_ROOT_20);
}
std::vector<std::string> paths;
@@ -2224,23 +2370,31 @@
std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
}
- sp<IDumpstateDevice_1_0> dumpstate_device_1_0(IDumpstateDevice_1_0::getService());
- if (dumpstate_device_1_0 == nullptr) {
- MYLOGE("No IDumpstateDevice implementation\n");
+ // get dumpstate HAL AIDL implementation
+ std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal_handle_aidl(
+ GetDumpstateBoardAidlService());
+ if (dumpstate_hal_handle_aidl == nullptr) {
+ MYLOGI("No IDumpstateDevice AIDL implementation\n");
+ }
+
+ // get dumpstate HAL HIDL implementation, only if AIDL HAL implementation not found
+ sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_handle_hidl_1_0 = nullptr;
+ if (dumpstate_hal_handle_aidl == nullptr) {
+ dumpstate_hal_handle_hidl_1_0 = dumpstate_hal_hidl_1_0::IDumpstateDevice::getService();
+ if (dumpstate_hal_handle_hidl_1_0 == nullptr) {
+ MYLOGI("No IDumpstateDevice HIDL implementation\n");
+ }
+ }
+
+ // if neither HIDL nor AIDL implementation found, then return
+ if (dumpstate_hal_handle_hidl_1_0 == nullptr && dumpstate_hal_handle_aidl == nullptr) {
+ MYLOGE("Could not find IDumpstateDevice implementation\n");
return;
}
- using ScopedNativeHandle =
- std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
- ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
- [](native_handle_t* handle) {
- native_handle_close(handle);
- native_handle_delete(handle);
- });
- if (handle == nullptr) {
- MYLOGE("Could not create native_handle\n");
- return;
- }
+ // this is used to hold the file descriptors and when this variable goes out of scope
+ // the file descriptors are closed
+ std::vector<::ndk::ScopedFileDescriptor> dumpstate_fds;
// TODO(128270426): Check for consent in between?
for (size_t i = 0; i < paths.size(); i++) {
@@ -2253,65 +2407,26 @@
MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
return;
}
- handle.get()->data[i] = fd.release();
+
+ dumpstate_fds.emplace_back(fd.release());
+ // we call fd.release() here to make sure "fd" does not get closed
+ // after "fd" goes out of scope after this block.
+ // "fd" will be closed when "dumpstate_fds" goes out of scope
+ // i.e. when we exit this function
}
// Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
// of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
// will kill the HAL and grab whatever it dumped in time.
- constexpr size_t timeout_sec = 30;
- // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
- // implement just 1.0.
- const char* descriptor_to_kill;
- using DumpstateBoardTask = std::packaged_task<bool()>;
- DumpstateBoardTask dumpstate_board_task;
- sp<IDumpstateDevice_1_1> dumpstate_device_1_1(
- IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0));
- if (dumpstate_device_1_1 != nullptr) {
- MYLOGI("Using IDumpstateDevice v1.1");
- descriptor_to_kill = IDumpstateDevice_1_1::descriptor;
- dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool {
- ::android::hardware::Return<DumpstateStatus> status =
- dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode,
- SEC_TO_MSEC(timeout_sec));
- if (!status.isOk()) {
- MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
- return false;
- } else if (status != DumpstateStatus::OK) {
- MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str());
- return false;
- }
- return true;
- });
- } else {
- MYLOGI("Using IDumpstateDevice v1.0");
- descriptor_to_kill = IDumpstateDevice_1_0::descriptor;
- dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool {
- ::android::hardware::Return<void> status =
- dumpstate_device_1_0->dumpstateBoard(handle.get());
- if (!status.isOk()) {
- MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
- return false;
- }
- return true;
- });
- }
- auto result = dumpstate_board_task.get_future();
- std::thread(std::move(dumpstate_board_task)).detach();
+ constexpr size_t timeout_sec = 45;
- if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
- MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
- if (!android::base::SetProperty(
- "ctl.interface_restart",
- android::base::StringPrintf("%s/default", descriptor_to_kill))) {
- MYLOGE("Couldn't restart dumpstate HAL\n");
- }
- }
- // Wait some time for init to kill dumpstate vendor HAL
- constexpr size_t killing_timeout_sec = 10;
- if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
- MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
- "there might be racing in content\n", killing_timeout_sec);
+ if (dumpstate_hal_handle_aidl != nullptr) {
+ DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
+ timeout_sec);
+ } else if (dumpstate_hal_handle_hidl_1_0 != nullptr) {
+ // run HIDL HAL only if AIDL HAL not found
+ DoDumpstateBoardHidl(dumpstate_hal_handle_hidl_1_0, dumpstate_fds, options_->bugreport_mode,
+ timeout_sec);
}
if (mount_debugfs) {
@@ -2324,9 +2439,8 @@
auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
for (size_t i = 0; i < paths.size(); i++) {
struct stat s;
- if (fstat(handle.get()->data[i], &s) == -1) {
- MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
- strerror(errno));
+ if (fstat(dumpstate_fds[i].get(), &s) == -1) {
+ MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(), strerror(errno));
file_sizes[i] = -1;
continue;
}
@@ -2565,40 +2679,35 @@
bool is_screenshot_requested) {
// Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for
// default system screenshots.
- options->bugreport_mode = ModeToString(mode);
+ options->bugreport_mode = mode;
+ options->bugreport_mode_string = ModeToString(mode);
switch (mode) {
case Dumpstate::BugreportMode::BUGREPORT_FULL:
options->do_screenshot = is_screenshot_requested;
- options->dumpstate_hal_mode = DumpstateMode::FULL;
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
// Currently, the dumpstate binder is only used by Shell to update progress.
options->do_progress_updates = true;
options->do_screenshot = is_screenshot_requested;
- options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
break;
case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
options->do_vibrate = false;
options->is_remote_mode = true;
options->do_screenshot = false;
- options->dumpstate_hal_mode = DumpstateMode::REMOTE;
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
options->do_progress_updates = true;
options->do_screenshot = is_screenshot_requested;
- options->dumpstate_hal_mode = DumpstateMode::WEAR;
break;
// TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
options->do_progress_updates = true;
options->do_screenshot = false;
- options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY;
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
options->wifi_only = true;
options->do_screenshot = false;
- options->dumpstate_hal_mode = DumpstateMode::WIFI;
break;
case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
break;
@@ -2609,13 +2718,14 @@
MYLOGI(
"do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
"is_remote_mode: %d show_header_only: %d telephony_only: %d "
- "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
+ "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s "
"limited_only: %d args: %s\n",
options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
options.do_screenshot, options.is_remote_mode, options.show_header_only,
options.telephony_only, options.wifi_only,
- options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
- toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str());
+ options.do_progress_updates, options.bugreport_fd.get(),
+ options.bugreport_mode_string.c_str(),
+ options.limited_only, options.args.c_str());
}
void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
@@ -2623,8 +2733,8 @@
const android::base::unique_fd& screenshot_fd_in,
bool is_screenshot_requested) {
// Duplicate the fds because the passed in fds don't outlive the binder transaction.
- bugreport_fd.reset(dup(bugreport_fd_in.get()));
- screenshot_fd.reset(dup(screenshot_fd_in.get()));
+ bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0));
+ screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0));
SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
}
@@ -2795,10 +2905,9 @@
version_ = VERSION_CURRENT;
}
- if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) {
- MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n",
- version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(),
- VERSION_SPLIT_ANR.c_str());
+ if (version_ != VERSION_CURRENT) {
+ MYLOGE("invalid version requested ('%s'); supported values are: ('%s', '%s')\n",
+ version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str());
return RunStatus::INVALID_INPUT;
}
@@ -2829,7 +2938,7 @@
}
MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n",
- id_, options_->args.c_str(), options_->bugreport_mode.c_str(), version_.c_str());
+ id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str());
do_early_screenshot_ = options_->do_progress_updates;
@@ -3124,8 +3233,7 @@
void Dumpstate::ShutdownDumpPool() {
if (dump_pool_) {
- dump_pool_->shutdown();
- dump_pool_ = nullptr;
+ dump_pool_.reset();
}
if (zip_entry_tasks_) {
zip_entry_tasks_->run(/* do_cancel = */true);
@@ -3405,10 +3513,6 @@
dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
}
-bool Dumpstate::IsZipping() const {
- return zip_writer_ != nullptr;
-}
-
std::string Dumpstate::GetPath(const std::string& suffix) const {
return GetPath(bugreport_internal_dir_, suffix);
}
@@ -4054,10 +4158,6 @@
}
void dump_frozen_cgroupfs() {
- if (!ds.IsZipping()) {
- MYLOGD("Not adding cgroupfs because it's not a zipped bugreport\n");
- return;
- }
MYLOGD("Adding frozen processes from %s\n", CGROUPFS_DIR);
DurationReporter duration_reporter("FROZEN CGROUPFS");
if (PropertiesHelper::IsDryRun()) return;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 34280d0..ee6b1ae 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -25,6 +25,7 @@
#include <string>
#include <vector>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.1/types.h>
@@ -38,11 +39,6 @@
#include "DumpPool.h"
#include "TaskQueue.h"
-// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
-// std::vector<std::string>
-// TODO: remove once not used
-#define MAX_ARGS_ARRAY_SIZE 1000
-
// TODO: move everything under this namespace
// TODO: and then remove explicitly android::os::dumpstate:: prefixes
namespace android {
@@ -161,12 +157,6 @@
static std::string VERSION_CURRENT = "2.0";
/*
- * Temporary version that adds a anr-traces.txt entry. Once tools support it, the current version
- * will be bumped to 3.0.
- */
-static std::string VERSION_SPLIT_ANR = "3.0-dev-split-anr";
-
-/*
* "Alias" for the current version.
*/
static std::string VERSION_DEFAULT = "default";
@@ -218,9 +208,6 @@
static Dumpstate& GetInstance();
- /* Checkes whether dumpstate is generating a zipped bugreport. */
- bool IsZipping() const;
-
/* Initialize dumpstate fields before starting bugreport generation */
void Initialize();
@@ -405,19 +392,18 @@
bool limited_only = false;
// Whether progress updates should be published.
bool do_progress_updates = false;
- // The mode we'll use when calling IDumpstateDevice::dumpstateBoard.
+ // this is used to derive dumpstate HAL bug report mode
// TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead.
// The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
- ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
- ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
+ BugreportMode bugreport_mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
// File descriptor to output zip file. Takes precedence over out_dir.
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
android::base::unique_fd screenshot_fd;
// Custom output directory.
std::string out_dir;
- // Bugreport mode of the bugreport.
- std::string bugreport_mode;
+ // Bugreport mode of the bugreport as a string
+ std::string bugreport_mode_string;
// Command-line arguments as string
std::string args;
// Notification title and description
@@ -492,7 +478,7 @@
// This is useful for debugging.
std::string log_path_;
- // Full path of the bugreport file, be it zip or text, inside bugreport_internal_dir_.
+ // Full path of the bugreport zip file inside bugreport_internal_dir_.
std::string path_;
// Full path of the file containing the screenshot (when requested).
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index db508b5..70b4e5c 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -33,6 +33,7 @@
#include <unistd.h>
#include <thread>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -47,6 +48,7 @@
namespace os {
namespace dumpstate {
+using DumpstateDeviceAidl = ::aidl::android::hardware::dumpstate::IDumpstateDevice;
using ::android::hardware::dumpstate::V1_1::DumpstateMode;
using ::testing::EndsWith;
using ::testing::Eq;
@@ -186,7 +188,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -210,7 +211,6 @@
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
@@ -234,13 +234,11 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -256,7 +254,6 @@
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -272,7 +269,6 @@
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
// Other options retain default values
EXPECT_FALSE(options_.progress_updates_to_socket);
@@ -286,7 +282,7 @@
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_TRUE(options_.do_progress_updates);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
+
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -302,7 +298,6 @@
EXPECT_FALSE(options_.do_screenshot);
EXPECT_TRUE(options_.telephony_only);
EXPECT_TRUE(options_.do_progress_updates);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -317,7 +312,6 @@
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_TRUE(options_.wifi_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -354,7 +348,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.stream_to_socket);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
@@ -371,7 +364,6 @@
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -408,7 +400,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -436,7 +427,6 @@
EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeHelp) {
@@ -1730,14 +1720,13 @@
dprintf(out_fd, "C");
};
setLogDuration(/* log_duration = */false);
- dump_pool_->enqueueTaskWithFd(/* task_name = */"1", dump_func_1, std::placeholders::_1);
- dump_pool_->enqueueTaskWithFd(/* task_name = */"2", dump_func_2, std::placeholders::_1);
- dump_pool_->enqueueTaskWithFd(/* task_name = */"3", dump_func_3, std::placeholders::_1);
+ auto t1 = dump_pool_->enqueueTaskWithFd("", dump_func_1, std::placeholders::_1);
+ auto t2 = dump_pool_->enqueueTaskWithFd("", dump_func_2, std::placeholders::_1);
+ auto t3 = dump_pool_->enqueueTaskWithFd("", dump_func_3, std::placeholders::_1);
- dump_pool_->waitForTask("1", "", out_fd_.get());
- dump_pool_->waitForTask("2", "", out_fd_.get());
- dump_pool_->waitForTask("3", "", out_fd_.get());
- dump_pool_->shutdown();
+ WaitForTask(std::move(t1), "", out_fd_.get());
+ WaitForTask(std::move(t2), "", out_fd_.get());
+ WaitForTask(std::move(t3), "", out_fd_.get());
std::string result;
ReadFileToString(out_path_, &result);
@@ -1751,9 +1740,8 @@
run_1 = true;
};
- dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
- dump_pool_->waitForTask("1", "", out_fd_.get());
- dump_pool_->shutdown();
+ auto t1 = dump_pool_->enqueueTask(/* duration_title = */"1", dump_func_1);
+ WaitForTask(std::move(t1), "", out_fd_.get());
std::string result;
ReadFileToString(out_path_, &result);
@@ -1762,27 +1750,6 @@
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 6ab6b7f..ceb16cb 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -64,6 +64,10 @@
srcs: [
"main.cpp",
],
+
+ shared_libs: [
+ "packagemanager_aidl-cpp",
+ ],
}
cc_binary {
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index ba1c449..3d2bdf1 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -21,9 +21,12 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <binder/BpBinder.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <binder/Stability.h>
#include <binder/TextOutput.h>
#include <binderdebug/BinderDebug.h>
#include <serviceutils/PriorityDumper.h>
@@ -57,25 +60,30 @@
}
static void usage() {
- fprintf(stderr,
- "usage: dumpsys\n"
- " To dump all services.\n"
- "or:\n"
- " 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"
- " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
- " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
- " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
+ fprintf(
+ stderr,
+ "usage: dumpsys\n"
+ " To dump all services.\n"
+ "or:\n"
+ " dumpsys [-t TIMEOUT] [--priority LEVEL] [--clients] [--dump] [--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"
+ " --clients: dump client PIDs instead of usual dump\n"
+ " --dump: ask the service to dump itself (this is the default)\n"
+ " --pid: dump PID 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"
+ " LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
+ " --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
+ " --stability: dump binder stability information instead of usual dump\n"
+ " --thread: dump thread usage instead of usual dump\n"
+ " SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
@@ -125,16 +133,15 @@
bool showListOnly = false;
bool skipServices = false;
bool asProto = false;
- Type type = Type::DUMP;
+ int dumpTypeFlags = 0;
int timeoutArgMs = 10000;
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
- 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},
- {"help", no_argument, 0, 0},
- {0, 0, 0, 0}};
+ static struct option longOptions[] = {
+ {"help", no_argument, 0, 0}, {"clients", no_argument, 0, 0},
+ {"dump", no_argument, 0, 0}, {"pid", no_argument, 0, 0},
+ {"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0},
+ {"skip", no_argument, 0, 0}, {"stability", no_argument, 0, 0},
+ {"thread", no_argument, 0, 0}, {0, 0, 0, 0}};
// Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
// happens on test cases).
@@ -165,10 +172,16 @@
usage();
return -1;
}
+ } else if (!strcmp(longOptions[optionIndex].name, "dump")) {
+ dumpTypeFlags |= TYPE_DUMP;
} else if (!strcmp(longOptions[optionIndex].name, "pid")) {
- type = Type::PID;
+ dumpTypeFlags |= TYPE_PID;
+ } else if (!strcmp(longOptions[optionIndex].name, "stability")) {
+ dumpTypeFlags |= TYPE_STABILITY;
} else if (!strcmp(longOptions[optionIndex].name, "thread")) {
- type = Type::THREAD;
+ dumpTypeFlags |= TYPE_THREAD;
+ } else if (!strcmp(longOptions[optionIndex].name, "clients")) {
+ dumpTypeFlags |= TYPE_CLIENTS;
}
break;
@@ -206,6 +219,10 @@
}
}
+ if (dumpTypeFlags == 0) {
+ dumpTypeFlags = TYPE_DUMP;
+ }
+
for (int i = optind; i < argc; i++) {
if (skipServices) {
skippedServices.add(String16(argv[i]));
@@ -258,7 +275,7 @@
const String16& serviceName = services[i];
if (IsSkipped(skippedServices, serviceName)) continue;
- if (startDumpThread(type, serviceName, args) == OK) {
+ if (startDumpThread(dumpTypeFlags, serviceName, args) == OK) {
bool addSeparator = (N > 1);
if (addSeparator) {
writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
@@ -325,16 +342,24 @@
}
}
-static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) {
+static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd, bool exclusive) {
pid_t pid;
status_t status = service->getDebugPid(&pid);
if (status != OK) {
return status;
}
+ if (!exclusive) {
+ WriteStringToFd("Service host process PID: ", fd.get());
+ }
WriteStringToFd(std::to_string(pid) + "\n", fd.get());
return OK;
}
+static status_t dumpStabilityToFd(const sp<IBinder>& service, const unique_fd& fd) {
+ WriteStringToFd("Stability: " + internal::Stability::debugToString(service) + "\n", fd);
+ return OK;
+}
+
static status_t dumpThreadsToFd(const sp<IBinder>& service, const unique_fd& fd) {
pid_t pid;
status_t status = service->getDebugPid(&pid);
@@ -352,7 +377,43 @@
return OK;
}
-status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
+static status_t dumpClientsToFd(const sp<IBinder>& service, const unique_fd& fd) {
+ std::string clientPids;
+ const auto remoteBinder = service->remoteBinder();
+ if (remoteBinder == nullptr) {
+ WriteStringToFd("Client PIDs are not available for local binders.\n", fd.get());
+ return OK;
+ }
+ const auto handle = remoteBinder->getDebugBinderHandle();
+ if (handle == std::nullopt) {
+ return OK;
+ }
+ std::vector<pid_t> pids;
+ pid_t myPid = getpid();
+ pid_t servicePid;
+ status_t status = service->getDebugPid(&servicePid);
+ if (status != OK) {
+ return status;
+ }
+ status =
+ getBinderClientPids(BinderDebugContext::BINDER, myPid, servicePid, handle.value(), &pids);
+ if (status != OK) {
+ return status;
+ }
+ pids.erase(std::remove_if(pids.begin(), pids.end(), [&](pid_t pid) { return pid == myPid; }),
+ pids.end());
+ WriteStringToFd("Client PIDs: " + ::android::base::Join(pids, ", ") + "\n", fd.get());
+ return OK;
+}
+
+static void reportDumpError(const String16& serviceName, status_t error, const char* context) {
+ if (error == OK) return;
+
+ std::cerr << "Error with service '" << serviceName << "' while " << context << ": "
+ << statusToString(error) << std::endl;
+}
+
+status_t Dumpsys::startDumpThread(int dumpTypeFlags, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
if (service == nullptr) {
@@ -373,26 +434,27 @@
// dump blocks until completion, so spawn a thread..
activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
- status_t err = 0;
-
- switch (type) {
- case Type::DUMP:
- err = service->dump(remote_end.get(), args);
- break;
- 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;
+ if (dumpTypeFlags & TYPE_PID) {
+ status_t err = dumpPidToFd(service, remote_end, dumpTypeFlags == TYPE_PID);
+ reportDumpError(serviceName, err, "dumping PID");
+ }
+ if (dumpTypeFlags & TYPE_STABILITY) {
+ status_t err = dumpStabilityToFd(service, remote_end);
+ reportDumpError(serviceName, err, "dumping stability");
+ }
+ if (dumpTypeFlags & TYPE_THREAD) {
+ status_t err = dumpThreadsToFd(service, remote_end);
+ reportDumpError(serviceName, err, "dumping thread info");
+ }
+ if (dumpTypeFlags & TYPE_CLIENTS) {
+ status_t err = dumpClientsToFd(service, remote_end);
+ reportDumpError(serviceName, err, "dumping clients info");
}
- if (err != OK) {
- std::cerr << "Error dumping service info status_t: " << statusToString(err) << " "
- << serviceName << std::endl;
+ // other types always act as a header, this is usually longer
+ if (dumpTypeFlags & TYPE_DUMP) {
+ status_t err = service->dump(remote_end.get(), args);
+ reportDumpError(serviceName, err, "dumping");
}
});
return OK;
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 349947c..6ab1a7d 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -51,23 +51,26 @@
*/
static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
- enum class Type {
- DUMP, // dump using `dump` function
- PID, // dump pid of server only
- THREAD, // dump thread usage of server only
+ enum Type {
+ TYPE_DUMP = 0x1, // dump using `dump` function
+ TYPE_PID = 0x2, // dump pid of server only
+ TYPE_STABILITY = 0x4, // dump stability information of server
+ TYPE_THREAD = 0x8, // dump thread usage of server only
+ TYPE_CLIENTS = 0x10, // dump pid of clients
};
/**
* 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 call to {@code
* stopDumpThread}.
+ * @param dumpTypeFlags operations to perform
* @param serviceName
* @param args list of arguments to pass to service dump method.
* @return {@code OK} thread is started successfully.
* {@code NAME_NOT_FOUND} service could not be found.
* {@code != OK} error
*/
- status_t startDumpThread(Type type, const String16& serviceName,
+ status_t startDumpThread(int dumpTypeFlags, const String16& serviceName,
const Vector<String16>& args);
/**
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index c9d2dbb..49c1318 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -60,6 +60,11 @@
MOCK_METHOD1(isDeclared, bool(const String16&));
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
+ MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&));
+ MOCK_METHOD2(registerForNotifications, status_t(const String16&,
+ const sp<LocalRegistrationCallback>&));
+ MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
+ const sp<LocalRegistrationCallback>&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
@@ -200,7 +205,7 @@
CaptureStdout();
CaptureStderr();
dump_.setServiceArgs(args, supportsProto, priorityFlags);
- status_t status = dump_.startDumpThread(Dumpsys::Type::DUMP, serviceName, args);
+ status_t status = dump_.startDumpThread(Dumpsys::TYPE_DUMP, serviceName, args);
EXPECT_THAT(status, Eq(0));
status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
elapsedDuration, bytesWritten);
@@ -582,6 +587,27 @@
AssertOutput(std::to_string(getpid()) + "\n");
}
+// Tests 'dumpsys --stability'
+TEST_F(DumpsysTest, ListAllServicesWithStability) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--stability"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+ AssertOutputContains("stability");
+}
+
+// Tests 'dumpsys --stability service_name'
+TEST_F(DumpsysTest, ListServiceWithStability) {
+ ExpectCheckService("Locksmith");
+
+ CallMain({"--stability", "Locksmith"});
+
+ AssertOutputContains("stability");
+}
+
// Tests 'dumpsys --thread'
TEST_F(DumpsysTest, ListAllServicesWithThread) {
ExpectListServices({"Locksmith", "Valet"});
@@ -606,6 +632,51 @@
AssertOutputFormat(format);
}
+// Tests 'dumpsys --clients'
+TEST_F(DumpsysTest, ListAllServicesWithClients) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--clients"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+
+ const std::string format("(.|\n)*((Client PIDs are not available for local binders.)(.|\n)*){2}");
+ AssertOutputFormat(format);
+}
+
+// Tests 'dumpsys --clients service_name'
+TEST_F(DumpsysTest, ListServiceWithClients) {
+ ExpectCheckService("Locksmith");
+
+ CallMain({"--clients", "Locksmith"});
+
+ const std::string format("Client PIDs are not available for local binders.\n");
+ AssertOutputFormat(format);
+}
+// Tests 'dumpsys --thread --stability'
+TEST_F(DumpsysTest, ListAllServicesWithMultipleOptions) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"--pid", "--stability"});
+ AssertRunningServices({"Locksmith", "Valet"});
+
+ AssertOutputContains(std::to_string(getpid()));
+ AssertOutputContains("stability");
+}
+
+// Tests 'dumpsys --pid --stability service_name'
+TEST_F(DumpsysTest, ListServiceWithMultipleOptions) {
+ ExpectCheckService("Locksmith");
+ CallMain({"--pid", "--stability", "Locksmith"});
+
+ AssertOutputContains(std::to_string(getpid()));
+ AssertOutputContains("stability");
+}
+
TEST_F(DumpsysTest, GetBytesWritten) {
const char* serviceName = "service2";
const char* dumpContents = "dump1";
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index ec3bc61..c18d3f5 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -24,7 +24,7 @@
cc_defaults {
name: "idlcli-defaults",
shared_libs: [
- "android.hardware.vibrator-V2-ndk_platform",
+ "android.hardware.vibrator-V2-ndk",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 3f180d9..c9f680b 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -28,6 +28,7 @@
"dexopt.cpp",
"execv_helper.cpp",
"globals.cpp",
+ "restorable_file.cpp",
"run_dex2oat.cpp",
"unique_file.cpp",
"utils.cpp",
@@ -45,10 +46,12 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "libziparchive",
"server_configurable_flags",
],
static_libs: [
"libasync_safe",
+ "libext2_uuid",
],
export_shared_lib_headers: [
"libbinder",
@@ -79,7 +82,7 @@
"-cert-err58-cpp",
],
tidy_flags: [
- "-warnings-as-errors=clang-analyzer-security*,cert-*"
+ "-warnings-as-errors=clang-analyzer-security*,cert-*",
],
}
@@ -131,7 +134,10 @@
"unique_file.cpp",
"execv_helper.cpp",
],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"libbase",
"server_configurable_flags",
@@ -169,7 +175,7 @@
// Needs to be wherever installd is as it's execed by
// installd.
- required: [ "migrate_legacy_obb_data.sh" ],
+ required: ["migrate_legacy_obb_data.sh"],
}
// OTA chroot tool
@@ -193,7 +199,7 @@
"libutils",
],
required: [
- "apexd"
+ "apexd",
],
}
@@ -212,7 +218,7 @@
name: "libotapreoptparameters",
cflags: [
"-Wall",
- "-Werror"
+ "-Werror",
],
srcs: ["otapreopt_parameters.cpp"],
@@ -236,7 +242,7 @@
name: "otapreopt",
cflags: [
"-Wall",
- "-Werror"
+ "-Werror",
],
srcs: [
@@ -245,6 +251,7 @@
"globals.cpp",
"otapreopt.cpp",
"otapreopt_utils.cpp",
+ "restorable_file.cpp",
"run_dex2oat.cpp",
"unique_file.cpp",
"utils.cpp",
@@ -256,6 +263,7 @@
"libasync_safe",
"libdiskusage",
"libotapreoptparameters",
+ "libext2_uuid",
],
shared_libs: [
@@ -267,6 +275,7 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "libziparchive",
"server_configurable_flags",
],
}
@@ -294,5 +303,5 @@
// Script to migrate legacy obb data.
sh_binary {
name: "migrate_legacy_obb_data.sh",
- src: "migrate_legacy_obb_data.sh"
+ src: "migrate_legacy_obb_data.sh",
}
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index e29ff4c..27690a3 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -116,6 +116,7 @@
break;
}
}
+ fts_close(fts);
} else {
if (tombstone) {
if (truncate(path.c_str(), 0) != 0) {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b84be9b..b6d786d 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -18,13 +18,10 @@
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
-#include <algorithm>
#include <errno.h>
-#include <fstream>
#include <fts.h>
-#include <functional>
#include <inttypes.h>
-#include <regex>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
@@ -39,6 +36,12 @@
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <functional>
+#include <regex>
+#include <unordered_set>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -52,7 +55,8 @@
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
-#include <log/log.h> // TODO: Move everything to base/logging.
+#include <linux/quota.h>
+#include <log/log.h> // TODO: Move everything to base/logging.
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
#include <private/android_projectid_config.h>
@@ -76,7 +80,10 @@
#define LOG_TAG "installd"
#endif
+// #define GRANULAR_LOCKS
+
using android::base::ParseUint;
+using android::base::Split;
using android::base::StringPrintf;
using std::endl;
@@ -100,11 +107,6 @@
static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
-// fsverity assumes the page size is always 4096. If not, the feature can not be
-// enabled.
-static constexpr int kVerityPageSize = 4096;
-static constexpr size_t kSha256Size = 32;
-static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
static constexpr const char* kFuseProp = "persist.sys.fuse";
/**
@@ -116,6 +118,12 @@
static std::atomic<bool> sAppDataIsolationEnabled(false);
+/**
+ * Flag to control if project ids are supported for internal storage
+ */
+static std::atomic<bool> sUsingProjectIdsFlag(false);
+static std::once_flag flag;
+
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -258,11 +266,103 @@
} \
}
-#define ASSERT_PAGE_SIZE_4K() { \
- if (getpagesize() != kVerityPageSize) { \
- return error("FSVerity only supports 4K pages"); \
- } \
-}
+#ifdef GRANULAR_LOCKS
+
+/**
+ * This class obtains in constructor and keeps the local strong pointer to the RefLock.
+ * On destruction, it checks if there are any other strong pointers, and remove the map entry if
+ * this was the last one.
+ */
+template <class Key, class Mutex>
+struct LocalLockHolder {
+ using WeakPointer = std::weak_ptr<Mutex>;
+ using StrongPointer = std::shared_ptr<Mutex>;
+ using Map = std::unordered_map<Key, WeakPointer>;
+ using MapLock = std::recursive_mutex;
+
+ LocalLockHolder(Key key, Map& map, MapLock& mapLock)
+ : mKey(std::move(key)), mMap(map), mMapLock(mapLock) {
+ std::lock_guard lock(mMapLock);
+ auto& weakPtr = mMap[mKey];
+
+ // Check if the RefLock is still alive.
+ mRefLock = weakPtr.lock();
+ if (!mRefLock) {
+ // Create a new lock.
+ mRefLock = std::make_shared<Mutex>();
+ weakPtr = mRefLock;
+ }
+ }
+ LocalLockHolder(LocalLockHolder&& other) noexcept
+ : mKey(std::move(other.mKey)),
+ mMap(other.mMap),
+ mMapLock(other.mMapLock),
+ mRefLock(std::move(other.mRefLock)) {
+ other.mRefLock.reset();
+ }
+ ~LocalLockHolder() {
+ if (!mRefLock) {
+ return;
+ }
+
+ std::lock_guard lock(mMapLock);
+ // Clear the strong pointer.
+ mRefLock.reset();
+ auto found = mMap.find(mKey);
+ if (found == mMap.end()) {
+ return;
+ }
+ const auto& weakPtr = found->second;
+ // If this was the last pointer then it's ok to remove the map entry.
+ if (weakPtr.expired()) {
+ mMap.erase(found);
+ }
+ }
+
+ void lock() { mRefLock->lock(); }
+ void unlock() { mRefLock->unlock(); }
+ void lock_shared() { mRefLock->lock_shared(); }
+ void unlock_shared() { mRefLock->unlock_shared(); }
+
+private:
+ Key mKey;
+ Map& mMap;
+ MapLock& mMapLock;
+ StrongPointer mRefLock;
+};
+
+using UserLock = LocalLockHolder<userid_t, std::shared_mutex>;
+using UserWriteLockGuard = std::unique_lock<UserLock>;
+using UserReadLockGuard = std::shared_lock<UserLock>;
+
+using PackageLock = LocalLockHolder<std::string, std::recursive_mutex>;
+using PackageLockGuard = std::lock_guard<PackageLock>;
+
+#define LOCK_USER() \
+ UserLock localUserLock(userId, mUserIdLock, mLock); \
+ UserWriteLockGuard userLock(localUserLock)
+
+#define LOCK_USER_READ() \
+ UserLock localUserLock(userId, mUserIdLock, mLock); \
+ UserReadLockGuard userLock(localUserLock)
+
+#define LOCK_PACKAGE() \
+ PackageLock localPackageLock(packageName, mPackageNameLock, mLock); \
+ PackageLockGuard packageLock(localPackageLock)
+
+#define LOCK_PACKAGE_USER() \
+ LOCK_USER_READ(); \
+ LOCK_PACKAGE()
+
+#else
+
+#define LOCK_USER() std::lock_guard lock(mLock)
+#define LOCK_PACKAGE() std::lock_guard lock(mLock)
+#define LOCK_PACKAGE_USER() \
+ (void)userId; \
+ std::lock_guard lock(mLock)
+
+#endif // GRANULAR_LOCKS
} // namespace
@@ -281,34 +381,29 @@
}
status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
- auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
const binder::Status dump_permission = checkPermission(kDump);
if (!dump_permission.isOk()) {
- out << dump_permission.toString8() << endl;
+ dprintf(fd, "%s\n", dump_permission.toString8().c_str());
return PERMISSION_DENIED;
}
- std::lock_guard<std::recursive_mutex> lock(mLock);
-
- out << "installd is happy!" << endl;
{
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
- out << endl << "Storage mounts:" << endl;
+ dprintf(fd, "Storage mounts:\n");
for (const auto& n : mStorageMounts) {
- out << " " << n.first << " = " << n.second << endl;
+ dprintf(fd, " %s = %s\n", n.first.c_str(), n.second.c_str());
}
}
{
std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
- out << endl << "Per-UID cache quotas:" << endl;
+ dprintf(fd, "Per-UID cache quotas:\n");
for (const auto& n : mCacheQuotas) {
- out << " " << n.first << " = " << n.second << endl;
+ dprintf(fd, " %d = %" PRId64 "\n", n.first, n.second);
}
}
- out << endl;
- out.flush();
+ dprintf(fd, "is_dexopt_blocked:%d\n", android::installd::is_dexopt_blocked());
return NO_ERROR;
}
@@ -323,10 +418,17 @@
int res = 0;
char* before = nullptr;
char* after = nullptr;
+ if (!existing) {
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
+ SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
+ PLOG(ERROR) << "Failed recursive restorecon for " << path;
+ goto fail;
+ }
+ return res;
+ }
// Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
// libselinux. Not needed here.
-
if (lgetfilecon(path.c_str(), &before) < 0) {
PLOG(ERROR) << "Failed before getfilecon for " << path;
goto fail;
@@ -363,20 +465,41 @@
return res;
}
-static int restorecon_app_data_lazy(const std::string& parent, const char* name,
- const std::string& seInfo, uid_t uid, bool existing) {
- return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seInfo, uid,
- existing);
+static bool internal_storage_has_project_id() {
+ // The following path is populated in setFirstBoot, so if this file is present
+ // then project ids can be used. Using call once to cache the result of this check
+ // to avoid having to check the file presence again and again.
+ std::call_once(flag, []() {
+ auto using_project_ids =
+ StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+ sUsingProjectIdsFlag = access(using_project_ids.c_str(), F_OK) == 0;
+ });
+ // return sUsingProjectIdsFlag;
+ return false;
}
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
- if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
+ long project_id) {
+ if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
PLOG(ERROR) << "Failed to prepare " << path;
return -1;
}
+ if (internal_storage_has_project_id()) {
+ return set_quota_project_id(path, project_id, true);
+ }
return 0;
}
+static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+ uid_t uid, gid_t gid, long project_id) {
+ auto path = StringPrintf("%s/%s", parent.c_str(), name);
+ int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+ if (ret == 0 && internal_storage_has_project_id()) {
+ return set_quota_project_id(path, project_id, true);
+ }
+ return ret;
+}
+
static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
return true;
@@ -424,13 +547,153 @@
return true;
}
-binder::Status InstalldNativeService::createAppData(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
+static bool chown_app_dir(const std::string& path, uid_t uid, uid_t previousUid, gid_t cacheGid) {
+ FTS* fts;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
+ return false;
+ }
+ for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+ if (p->fts_info == FTS_D && p->fts_level == 1
+ && (strcmp(p->fts_name, "cache") == 0
+ || strcmp(p->fts_name, "code_cache") == 0)) {
+ // Mark cache dirs
+ p->fts_number = 1;
+ } else {
+ // Inherit parent's number
+ p->fts_number = p->fts_parent->fts_number;
+ }
+
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (p->fts_statp->st_uid == previousUid) {
+ if (lchown(p->fts_path, uid, p->fts_number ? cacheGid : uid) != 0) {
+ PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+ }
+ } else {
+ LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected UID "
+ << p->fts_statp->st_uid << " instead of " << previousUid;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ return true;
+}
+
+static void chown_app_profile_dir(const std::string &packageName, int32_t appId, int32_t userId) {
+ uid_t uid = multiuser_get_uid(userId, appId);
+ gid_t sharedGid = multiuser_get_shared_gid(userId, appId);
+
+ const std::string profile_dir =
+ create_primary_current_profile_package_dir_path(userId, packageName);
+ char *argv[] = { (char*) profile_dir.c_str(), nullptr };
+ if (FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr)) {
+ for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (lchown(p->fts_path, uid, uid) != 0) {
+ PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ }
+
+ const std::string ref_profile_path =
+ create_primary_reference_profile_package_dir_path(packageName);
+ argv[0] = (char *) ref_profile_path.c_str();
+ if (FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr)) {
+ for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+ if (p->fts_info == FTS_D && p->fts_level == 0) {
+ if (chown(p->fts_path, AID_SYSTEM, sharedGid) != 0) {
+ PLOG(WARNING) << "Failed to chown " << p->fts_path;
+ }
+ continue;
+ }
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (lchown(p->fts_path, sharedGid, sharedGid) != 0) {
+ PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ }
+}
+
+static binder::Status createAppDataDirs(const std::string& path, int32_t uid, int32_t gid,
+ int32_t* previousUid, int32_t cacheGid,
+ const std::string& seInfo, mode_t targetMode,
+ long projectIdApp, long projectIdCache) {
+ struct stat st{};
+ bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
+
+ auto cache_path = StringPrintf("%s/%s", path.c_str(), "cache");
+ auto code_cache_path = StringPrintf("%s/%s", path.c_str(), "code_cache");
+ bool cache_exists = (access(cache_path.c_str(), F_OK) == 0);
+ bool code_cache_exists = (access(code_cache_path.c_str(), F_OK) == 0);
+
+ if (parent_dir_exists) {
+ if (*previousUid < 0) {
+ // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
+ // of the directory as previousUid. This is required because it is not always possible
+ // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
+ *previousUid = st.st_uid;
+ }
+ if (*previousUid != uid) {
+ if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+ return error("Failed to chown " + path);
+ }
+ }
+ }
+
+ // Prepare only the parent app directory
+ if (prepare_app_dir(path, targetMode, uid, gid, projectIdApp) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid, projectIdCache) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid, projectIdCache)) {
+ return error("Failed to prepare " + path);
+ }
+
+ // Consider restorecon over contents if label changed
+ if (restorecon_app_data_lazy(path, seInfo, uid, parent_dir_exists)) {
+ return error("Failed to restorecon " + path);
+ }
+
+ // If the parent dir exists, the restorecon would already have been done
+ // as a part of the recursive restorecon above
+ if (parent_dir_exists && !cache_exists
+ && restorecon_app_data_lazy(cache_path, seInfo, uid, false)) {
+ return error("Failed to restorecon " + cache_path);
+ }
+
+ // If the parent dir exists, the restorecon would already have been done
+ // as a part of the recursive restorecon above
+ if (parent_dir_exists && !code_cache_exists
+ && restorecon_app_data_lazy(code_cache_path, seInfo, uid, false)) {
+ return error("Failed to restorecon " + code_cache_path);
+ }
+ return ok();
+}
+
+binder::Status InstalldNativeService::createAppDataLocked(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int32_t targetSdkVersion, int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -439,6 +702,14 @@
if (_aidl_return != nullptr) *_aidl_return = -1;
int32_t uid = multiuser_get_uid(userId, appId);
+
+ // If previousAppId < 0, we will use the existing app data owner as previousAppUid
+ // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
+ // if previousAppId > 0, an app is upgrading and changing its app ID
+ int32_t previousUid = previousAppId > 0
+ ? (int32_t) multiuser_get_uid(userId, previousAppId)
+ : (previousAppId == 0 ? uid : -1);
+
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
@@ -447,21 +718,16 @@
cacheGid = uid;
}
+ long projectIdApp = get_project_id(uid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
- bool existing = (access(path.c_str(), F_OK) == 0);
- if (prepare_app_dir(path, targetMode, uid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
- return error("Failed to prepare " + path);
- }
-
- // Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
- return error("Failed to restorecon " + path);
+ auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
+ if (!status.isOk()) {
+ return status;
}
// Remember inode numbers of cache directories so that we can clear
@@ -483,38 +749,97 @@
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- bool existing = (access(path.c_str(), F_OK) == 0);
- if (prepare_app_dir(path, targetMode, uid) ||
- prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
- prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
- return error("Failed to prepare " + path);
+ auto status = createAppDataDirs(path, uid, uid, &previousUid, cacheGid, seInfo, targetMode,
+ projectIdApp, projectIdCache);
+ if (!status.isOk()) {
+ return status;
}
-
- // Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
- restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
- return error("Failed to restorecon " + path);
+ if (previousUid != uid) {
+ chown_app_profile_dir(packageName, appId, userId);
}
if (!prepare_app_profile_dir(packageName, appId, userId)) {
return error("Failed to prepare profiles for " + packageName);
}
}
+
+ if (flags & FLAG_STORAGE_SDK) {
+ // Safe to ignore status since we can retry creating this by calling reconcileSdkData
+ auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+ if (!ignore.isOk()) {
+ PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
+ }
+
+ } else {
+ // Package does not need sdk storage. Remove it.
+ destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+ }
+
return ok();
}
+/**
+ * Responsible for creating /data/misc_{ce|de}/user/0/sdksandbox/<package-name> directory and other
+ * app level sub directories, such as ./shared
+ */
+binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t appId, int32_t flags) {
+ int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ if (sdkSandboxUid == -1) {
+ // There no valid sdk sandbox process for this app. Skip creation of data directory
+ return ok();
+ }
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+ // /data/misc_{ce,de}/<user-id>/sdksandbox directory gets created by vold
+ // during user creation
+
+ // Prepare the package directory
+ auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+ packageName.c_str());
+#if SDK_DEBUG
+ LOG(DEBUG) << "Creating app-level sdk data directory: " << packagePath;
+#endif
+
+ if (prepare_app_dir(packagePath, 0751, AID_SYSTEM, AID_SYSTEM, 0)) {
+ return error("Failed to prepare " + packagePath);
+ }
+ }
+
+ return ok();
+}
+
+binder::Status InstalldNativeService::createAppData(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int32_t targetSdkVersion, int64_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ LOCK_PACKAGE_USER();
+ return createAppDataLocked(uuid, packageName, userId, flags, appId, previousAppId, seInfo,
+ targetSdkVersion, _aidl_return);
+}
binder::Status InstalldNativeService::createAppData(
const android::os::CreateAppDataArgs& args,
android::os::CreateAppDataResult* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ // Locking is performed depeer in the callstack.
int64_t ceDataInode = -1;
auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId,
- args.seInfo, args.targetSdkVersion, &ceDataInode);
+ args.previousAppId, args.seInfo, args.targetSdkVersion, &ceDataInode);
_aidl_return->ceDataInode = ceDataInode;
_aidl_return->exceptionCode = status.exceptionCode();
_aidl_return->exceptionMessage = status.exceptionMessage();
@@ -525,10 +850,10 @@
const std::vector<android::os::CreateAppDataArgs>& args,
std::vector<android::os::CreateAppDataResult>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ // Locking is performed depeer in the callstack.
std::vector<android::os::CreateAppDataResult> results;
- for (auto arg : args) {
+ for (const auto &arg : args) {
android::os::CreateAppDataResult result;
createAppData(arg, &result);
results.push_back(result);
@@ -537,12 +862,117 @@
return ok();
}
+binder::Status InstalldNativeService::reconcileSdkData(
+ const android::os::ReconcileSdkDataArgs& args) {
+ // Locking is performed depeer in the callstack.
+
+ return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
+ args.previousAppId, args.seInfo, args.flags);
+}
+
+/**
+ * Reconciles per-sdk directory under app-level sdk data directory.
+
+ * E.g. `/data/misc_ce/0/sdksandbox/<package-name>/<sdkPackageName>-<randomSuffix>
+ *
+ * - If the sdk data package directory is missing, we create it first.
+ * - If sdkPackageNames is empty, we delete sdk package directory since it's not needed anymore.
+ * - If a sdk level directory we need to prepare already exist, we skip creating it again. This
+ * is to avoid having same per-sdk directory with different suffix.
+ * - If a sdk level directory exist which is absent from sdkPackageNames, we remove it.
+ */
+binder::Status InstalldNativeService::reconcileSdkData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ const std::vector<std::string>& subDirNames,
+ int userId, int appId, int previousAppId,
+ const std::string& seInfo, int flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ LOCK_PACKAGE_USER();
+
+#if SDK_DEBUG
+ LOG(DEBUG) << "Creating per sdk data directory for: " << packageName;
+#endif
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ // Prepare the sdk package directory in case it's missing
+ const auto status =
+ createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ auto res = ok();
+ // We have to create sdk data for CE and DE storage
+ const int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+
+ const auto packagePath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId,
+ packageName.c_str());
+
+ // Remove existing sub-directories not referred in subDirNames
+ const std::unordered_set<std::string> expectedSubDirNames(subDirNames.begin(),
+ subDirNames.end());
+ const auto subDirHandler = [&packagePath, &expectedSubDirNames,
+ &res](const std::string& subDirName) {
+ // Remove the per-sdk directory if it is not referred in
+ // expectedSubDirNames
+ if (expectedSubDirNames.find(subDirName) == expectedSubDirNames.end()) {
+ auto path = packagePath + "/" + subDirName;
+ if (delete_dir_contents_and_dir(path) != 0) {
+ res = error("Failed to delete " + path);
+ return;
+ }
+ }
+ };
+ const int ec = foreach_subdir(packagePath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to process subdirs for " + packagePath);
+ continue;
+ }
+
+ // Now create the subDirNames
+ for (const auto& subDirName : subDirNames) {
+ const std::string path =
+ create_data_misc_sdk_sandbox_sdk_path(uuid_, isCeData, userId,
+ packageName.c_str(), subDirName.c_str());
+
+ // Create the directory along with cache and code_cache
+ const int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid == -1) {
+ return exception(binder::Status::EX_ILLEGAL_STATE,
+ StringPrintf("cacheGid cannot be -1 for sdk data"));
+ }
+ const int32_t sandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ int32_t previousSandboxUid = multiuser_get_sdk_sandbox_uid(userId, previousAppId);
+ int32_t appUid = multiuser_get_uid(userId, appId);
+ long projectIdApp = get_project_id(appUid, PROJECT_ID_APP_START);
+ long projectIdCache = get_project_id(appUid, PROJECT_ID_APP_CACHE_START);
+ auto status =
+ createAppDataDirs(path, sandboxUid, AID_NOBODY, &previousSandboxUid, cacheGid,
+ seInfo, 0700 | S_ISGID, projectIdApp, projectIdCache);
+ if (!status.isOk()) {
+ res = status;
+ continue;
+ }
+ }
+ }
+
+ return res;
+}
+
binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -586,7 +1016,7 @@
const std::string& profileName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
binder::Status res = ok();
if (!clear_primary_reference_profile(packageName, profileName)) {
@@ -603,7 +1033,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -626,14 +1056,11 @@
}
}
if (flags & FLAG_STORAGE_DE) {
- std::string suffix = "";
- bool only_cache = false;
+ std::string suffix;
if (flags & FLAG_CLEAR_CACHE_ONLY) {
suffix = CACHE_DIR_POSTFIX;
- only_cache = true;
} else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
suffix = CODE_CACHE_DIR_POSTFIX;
- only_cache = true;
}
auto path = create_data_user_de_package_path(uuid_, userId, pkgname) + suffix;
@@ -685,6 +1112,47 @@
}
}
}
+ auto status = clearSdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+ if (!status.isOk()) {
+ res = status;
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags) {
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ binder::Status res = ok();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int i = 0; i < 2; i++) {
+ int currentFlag = storageFlags[i];
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ std::string suffix;
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ suffix = CACHE_DIR_POSTFIX;
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ suffix = CODE_CACHE_DIR_POSTFIX;
+ }
+
+ auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+ if (access(appPath.c_str(), F_OK) != 0) continue;
+ const auto subDirHandler = [&appPath, &res, &suffix](const std::string& filename) {
+ auto filepath = appPath + "/" + filename + suffix;
+ if (delete_dir_contents(filepath, true) != 0) {
+ res = error("Failed to clear contents of " + filepath);
+ }
+ };
+ const int ec = foreach_subdir(appPath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to process subdirs for " + appPath);
+ }
+ }
return res;
}
@@ -703,7 +1171,7 @@
binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
binder::Status res = ok();
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
@@ -723,7 +1191,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -731,13 +1199,13 @@
binder::Status res = ok();
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
- if (delete_dir_contents_and_dir(path) != 0) {
+ if (rename_delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
- if (delete_dir_contents_and_dir(path) != 0) {
+ if (rename_delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
if ((flags & FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
@@ -771,7 +1239,6 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
}
-
path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete contents of " + path);
@@ -782,6 +1249,32 @@
}
}
}
+ auto status = destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
+ if (!status.isOk()) {
+ res = status;
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags) {
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ binder::Status res = ok();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int i = 0; i < 2; i++) {
+ int currentFlag = storageFlags[i];
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ auto appPath = create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgname);
+ if (rename_delete_dir_contents_and_dir(appPath) != 0) {
+ res = error("Failed to delete " + appPath);
+ }
+ }
return res;
}
@@ -794,15 +1287,15 @@
int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
- std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- for (auto user : get_known_users(uuid_)) {
+ for (auto userId : get_known_users(uuid_)) {
+ LOCK_USER();
ATRACE_BEGIN("fixup user");
FTS* fts;
FTSENT* p;
- auto ce_path = create_data_user_ce_path(uuid_, user);
- auto de_path = create_data_user_de_path(uuid_, user);
+ auto ce_path = create_data_user_ce_path(uuid_, userId);
+ auto de_path = create_data_user_de_path(uuid_, userId);
char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
return error("Failed to fts_open");
@@ -894,29 +1387,28 @@
}
static int32_t copy_directory_recursive(const char* from, const char* to) {
- char *argv[] = {
- (char*) kCpPath,
- (char*) "-F", /* delete any existing destination file first (--remove-destination) */
- (char*) "-p", /* preserve timestamps, ownership, and permissions */
- (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
- (char*) "-P", /* Do not follow symlinks [default] */
- (char*) "-d", /* don't dereference symlinks */
- (char*) from,
- (char*) to
- };
+ char* argv[] =
+ {(char*)kCpPath,
+ (char*)"-F", /* delete any existing destination file first (--remove-destination) */
+ (char*)"--preserve=mode,ownership,timestamps,xattr", /* preserve properties */
+ (char*)"-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*)"-P", /* Do not follow symlinks [default] */
+ (char*)"-d", /* don't dereference symlinks */
+ (char*)from,
+ (char*)to};
LOG(DEBUG) << "Copying " << from << " to " << to;
return logwrap_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
}
-binder::Status InstalldNativeService::snapshotAppData(
- const std::optional<std::string>& volumeUuid,
- const std::string& packageName, int32_t user, int32_t snapshotId,
- int32_t storageFlags, int64_t* _aidl_return) {
+binder::Status InstalldNativeService::snapshotAppData(const std::optional<std::string>& volumeUuid,
+ const std::string& packageName,
+ int32_t userId, int32_t snapshotId,
+ int32_t storageFlags, int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
@@ -929,19 +1421,19 @@
bool clear_ce_on_exit = false;
bool clear_de_on_exit = false;
- auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
- &snapshotId] {
+ auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &userId, &package_name,
+ &snapshotId] {
if (clear_de_on_exit) {
- auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
- package_name);
+ auto to = create_data_misc_de_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete app data snapshot: " << to;
}
}
if (clear_ce_on_exit) {
- auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
- package_name);
+ auto to = create_data_misc_ce_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete app data snapshot: " << to;
}
@@ -951,10 +1443,11 @@
auto scope_guard = android::base::make_scope_guard(deleter);
if (storageFlags & FLAG_STORAGE_DE) {
- auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
- auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
- snapshotId, package_name);
+ auto from = create_data_user_de_package_path(volume_uuid, userId, package_name);
+ auto to = create_data_misc_de_rollback_path(volume_uuid, userId, snapshotId);
+ auto rollback_package_path =
+ create_data_misc_de_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
if (rc != 0) {
@@ -978,15 +1471,15 @@
}
// The app may not have any data at all, in which case it's OK to skip here.
- auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name);
+ auto from_ce = create_data_user_ce_package_path(volume_uuid, userId, package_name);
if (access(from_ce.c_str(), F_OK) != 0) {
LOG(INFO) << "Missing source " << from_ce;
return ok();
}
// ce_data_inode is not needed when FLAG_CLEAR_CACHE_ONLY is set.
- binder::Status clear_cache_result = clearAppData(volumeUuid, packageName, user,
- storageFlags | FLAG_CLEAR_CACHE_ONLY, 0);
+ binder::Status clear_cache_result =
+ clearAppData(volumeUuid, packageName, userId, storageFlags | FLAG_CLEAR_CACHE_ONLY, 0);
if (!clear_cache_result.isOk()) {
// It should be fine to continue snapshot if we for some reason failed
// to clear cache.
@@ -994,8 +1487,9 @@
}
// ce_data_inode is not needed when FLAG_CLEAR_CODE_CACHE_ONLY is set.
- binder::Status clear_code_cache_result = clearAppData(volumeUuid, packageName, user,
- storageFlags | FLAG_CLEAR_CODE_CACHE_ONLY, 0);
+ binder::Status clear_code_cache_result =
+ clearAppData(volumeUuid, packageName, userId, storageFlags | FLAG_CLEAR_CODE_CACHE_ONLY,
+ 0);
if (!clear_code_cache_result.isOk()) {
// It should be fine to continue snapshot if we for some reason failed
// to clear code_cache.
@@ -1003,10 +1497,11 @@
}
if (storageFlags & FLAG_STORAGE_CE) {
- auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
- auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
- snapshotId, package_name);
+ auto from = create_data_user_ce_package_path(volume_uuid, userId, package_name);
+ auto to = create_data_misc_ce_rollback_path(volume_uuid, userId, snapshotId);
+ auto rollback_package_path =
+ create_data_misc_ce_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
if (rc != 0) {
@@ -1025,8 +1520,9 @@
return res;
}
if (_aidl_return != nullptr) {
- auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
- snapshotId, package_name);
+ auto ce_snapshot_path =
+ create_data_misc_ce_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
if (rc != 0) {
res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
@@ -1041,20 +1537,20 @@
binder::Status InstalldNativeService::restoreAppDataSnapshot(
const std::optional<std::string>& volumeUuid, const std::string& packageName,
- const int32_t appId, const std::string& seInfo, const int32_t user,
+ const int32_t appId, const std::string& seInfo, const int32_t userId,
const int32_t snapshotId, int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
- auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
- user, snapshotId, package_name);
- auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
- user, snapshotId, package_name);
+ auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
+ auto from_de = create_data_misc_de_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name);
const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
(access(from_ce.c_str(), F_OK) == 0);
@@ -1074,14 +1570,14 @@
// It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
// can only be called when user unlocks the phone, meaning that CE user data
// is decrypted.
- binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
- 0 /* ceDataInode */);
+ binder::Status res =
+ clearAppData(volumeUuid, packageName, userId, storageFlags, 0 /* ceDataInode */);
if (!res.isOk()) {
return res;
}
if (needs_ce_rollback) {
- auto to_ce = create_data_user_ce_path(volume_uuid, user);
+ auto to_ce = create_data_user_ce_path(volume_uuid, userId);
int rc = copy_directory_recursive(from_ce.c_str(), to_ce.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from_ce + " to " + to_ce);
@@ -1091,11 +1587,11 @@
}
if (needs_de_rollback) {
- auto to_de = create_data_user_de_path(volume_uuid, user);
+ auto to_de = create_data_user_de_path(volume_uuid, userId);
int rc = copy_directory_recursive(from_de.c_str(), to_de.c_str());
if (rc != 0) {
if (needs_ce_rollback) {
- auto ce_data = create_data_user_ce_package_path(volume_uuid, user, package_name);
+ auto ce_data = create_data_user_ce_package_path(volume_uuid, userId, package_name);
LOG(WARNING) << "de_data rollback failed. Erasing rolled back ce_data " << ce_data;
if (delete_dir_contents(ce_data.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete rolled back ce_data " << ce_data;
@@ -1108,24 +1604,24 @@
}
// Finally, restore the SELinux label on the app data.
- return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo);
+ return restoreconAppData(volumeUuid, packageName, userId, storageFlags, appId, seInfo);
}
binder::Status InstalldNativeService::destroyAppDataSnapshot(
- const std::optional<std::string> &volumeUuid, const std::string& packageName,
- const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
+ const std::optional<std::string>& volumeUuid, const std::string& packageName,
+ const int32_t userId, const int64_t ceSnapshotInode, const int32_t snapshotId,
int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
if (storageFlags & FLAG_STORAGE_DE) {
- auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
- user, snapshotId, package_name);
+ auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid, userId,
+ snapshotId, package_name);
int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
if (res != 0) {
@@ -1134,8 +1630,9 @@
}
if (storageFlags & FLAG_STORAGE_CE) {
- auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
- user, snapshotId, package_name, ceSnapshotInode);
+ auto ce_snapshot_path =
+ create_data_misc_ce_rollback_package_path(volume_uuid, userId, snapshotId,
+ package_name, ceSnapshotInode);
int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
if (res != 0) {
return error(res, "Failed clearing snapshot " + ce_snapshot_path);
@@ -1145,15 +1642,15 @@
}
binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified(
- const std::optional<std::string> &volumeUuid, const int32_t user,
+ const std::optional<std::string>& volumeUuid, const int32_t userId,
const std::vector<int32_t>& retainSnapshotIds) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_USER();
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
- auto base_path = create_data_misc_ce_rollback_base_path(volume_uuid, user);
+ auto base_path = create_data_misc_ce_rollback_base_path(volume_uuid, userId);
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(base_path.c_str()), closedir);
if (!dir) {
@@ -1171,8 +1668,8 @@
if (parse_ok &&
std::find(retainSnapshotIds.begin(), retainSnapshotIds.end(),
snapshot_id) == retainSnapshotIds.end()) {
- auto rollback_path = create_data_misc_ce_rollback_path(
- volume_uuid, user, snapshot_id);
+ auto rollback_path =
+ create_data_misc_ce_rollback_path(volume_uuid, userId, snapshot_id);
int res = delete_dir_contents_and_dir(rollback_path, true /* ignore_if_missing */);
if (res != 0) {
return error(res, "Failed clearing snapshot " + rollback_path);
@@ -1190,7 +1687,7 @@
CHECK_ARGUMENT_UUID(fromUuid);
CHECK_ARGUMENT_UUID(toUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
@@ -1218,24 +1715,25 @@
}
// Copy private data for all known users
- for (auto user : users) {
+ for (auto userId : users) {
+ LOCK_USER();
// Data source may not exist for all users; that's okay
- auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name);
+ auto from_ce = create_data_user_ce_package_path(from_uuid, userId, package_name);
if (access(from_ce.c_str(), F_OK) != 0) {
LOG(INFO) << "Missing source " << from_ce;
continue;
}
- if (!createAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appId,
- seInfo, targetSdkVersion, nullptr).isOk()) {
+ if (!createAppDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+ appId, /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr)
+ .isOk()) {
res = error("Failed to create package target");
goto fail;
}
-
{
- auto from = create_data_user_de_package_path(from_uuid, user, package_name);
- auto to = create_data_user_de_path(to_uuid, user);
+ auto from = create_data_user_de_package_path(from_uuid, userId, package_name);
+ auto to = create_data_user_de_path(to_uuid, userId);
int rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
@@ -1244,8 +1742,8 @@
}
}
{
- auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
- auto to = create_data_user_ce_path(to_uuid, user);
+ auto from = create_data_user_ce_package_path(from_uuid, userId, package_name);
+ auto to = create_data_user_ce_path(to_uuid, userId);
int rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
@@ -1254,13 +1752,44 @@
}
}
- if (!restoreconAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
- appId, seInfo).isOk()) {
+ if (!restoreconAppDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+ appId, seInfo)
+ .isOk()) {
res = error("Failed to restorecon");
goto fail;
}
}
+ // Copy sdk data for all known users
+ for (auto userId : users) {
+ LOCK_USER();
+
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+
+ const auto from = create_data_misc_sdk_sandbox_package_path(from_uuid, isCeData, userId,
+ package_name);
+ if (access(from.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from;
+ continue;
+ }
+ const auto to = create_data_misc_sdk_sandbox_path(to_uuid, isCeData, userId);
+
+ const int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ goto fail;
+ }
+ }
+
+ if (!restoreconSdkDataLocked(toUuid, packageName, userId, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+ appId, seInfo)
+ .isOk()) {
+ res = error("Failed to restorecon");
+ goto fail;
+ }
+ }
// We let the framework scan the new location and persist that before
// deleting the data in the old location; this ordering ensures that
// we can recover from things like battery pulls.
@@ -1273,15 +1802,28 @@
LOG(WARNING) << "Failed to rollback " << to_app_package_path;
}
}
- for (auto user : users) {
+ for (auto userId : users) {
+ LOCK_USER();
{
- auto to = create_data_user_de_package_path(to_uuid, user, package_name);
+ auto to = create_data_user_de_package_path(to_uuid, userId, package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
}
{
- auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
+ auto to = create_data_user_ce_package_path(to_uuid, userId, package_name);
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ }
+ for (auto userId : users) {
+ LOCK_USER();
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ const bool isCeData = currentFlag == FLAG_STORAGE_CE;
+ const auto to = create_data_misc_sdk_sandbox_package_path(to_uuid, isCeData, userId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
@@ -1294,7 +1836,7 @@
int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
if (flags & FLAG_STORAGE_DE) {
@@ -1312,7 +1854,7 @@
int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
binder::Status res = ok();
@@ -1321,6 +1863,11 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
+ auto sdk_sandbox_de_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_de_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_de_path);
+ }
if (uuid_ == nullptr) {
path = create_data_misc_legacy_path(userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
@@ -1337,6 +1884,11 @@
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
+ auto sdk_sandbox_ce_path =
+ create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId);
+ if (delete_dir_contents_and_dir(sdk_sandbox_ce_path, true) != 0) {
+ res = error("Failed to delete " + sdk_sandbox_ce_path);
+ }
path = findDataMediaPath(uuid, userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
@@ -1349,7 +1901,9 @@
int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+#ifndef GRANULAR_LOCKS
+ std::lock_guard lock(mLock);
+#endif // !GRANULAR_LOCKS
auto uuidString = uuid.value_or("");
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
@@ -1376,13 +1930,24 @@
// 1. Create trackers for every known UID
ATRACE_BEGIN("create");
+ const auto users = get_known_users(uuid_);
+#ifdef GRANULAR_LOCKS
+ std::vector<UserLock> userLocks;
+ userLocks.reserve(users.size());
+ std::vector<UserWriteLockGuard> lockGuards;
+ lockGuards.reserve(users.size());
+#endif // GRANULAR_LOCKS
std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
- for (auto user : get_known_users(uuid_)) {
+ for (auto userId : users) {
+#ifdef GRANULAR_LOCKS
+ userLocks.emplace_back(userId, mUserIdLock, mLock);
+ lockGuards.emplace_back(userLocks.back());
+#endif // GRANULAR_LOCKS
FTS *fts;
FTSENT *p;
- auto ce_path = create_data_user_ce_path(uuid_, user);
- auto de_path = create_data_user_de_path(uuid_, user);
- auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
+ auto ce_path = create_data_user_ce_path(uuid_, userId);
+ auto de_path = create_data_user_de_path(uuid_, userId);
+ auto media_path = findDataMediaPath(uuid, userId) + "/Android/data/";
char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
(char*) media_path.c_str(), nullptr };
if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
@@ -1518,7 +2083,6 @@
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(codePath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
char dex_path[PKG_PATH_MAX];
@@ -1564,20 +2128,70 @@
return res.str();
}
#endif
+// On devices without sdcardfs, if internal and external are on
+// the same volume, a uid such as u0_a123 is used for both
+// internal and external storage; therefore, subtract that
+// amount from internal to make sure we don't count it double.
+// This needs to happen for data, cache and OBB
+static void deductDoubleSpaceIfNeeded(stats* stats, int64_t doubleSpaceToBeDeleted, uid_t uid,
+ const std::string& uuid) {
+ if (!supports_sdcardfs()) {
+ stats->dataSize -= doubleSpaceToBeDeleted;
+ long obbProjectId = get_project_id(uid, PROJECT_ID_EXT_OBB_START);
+ int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
+ stats->dataSize -= appObbSize;
+ }
+}
static void collectQuotaStats(const std::string& uuid, int32_t userId,
int32_t appId, struct stats* stats, struct stats* extStats) {
- int64_t space;
+ int64_t space, doubleSpaceToBeDeleted = 0;
uid_t uid = multiuser_get_uid(userId, appId);
- if (stats != nullptr) {
- if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
- stats->dataSize += space;
+ static const bool supportsProjectId = internal_storage_has_project_id();
+
+ if (extStats != nullptr) {
+ space = get_occupied_app_space_external(uuid, userId, appId);
+
+ if (space != -1) {
+ extStats->dataSize += space;
+ doubleSpaceToBeDeleted += space;
}
- int cacheGid = multiuser_get_cache_gid(userId, appId);
- if (cacheGid != -1) {
- if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ space = get_occupied_app_cache_space_external(uuid, userId, appId);
+ if (space != -1) {
+ extStats->dataSize += space; // cache counts for "data"
+ extStats->cacheSize += space;
+ doubleSpaceToBeDeleted += space;
+ }
+ }
+
+ if (stats != nullptr) {
+ if (!supportsProjectId) {
+ if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) {
+ stats->dataSize += space;
+ }
+ deductDoubleSpaceIfNeeded(stats, doubleSpaceToBeDeleted, uid, uuid);
+ int sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ if (sdkSandboxUid != -1) {
+ if ((space = GetOccupiedSpaceForUid(uuid, sdkSandboxUid)) != -1) {
+ stats->dataSize += space;
+ }
+ }
+ int cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid != -1) {
+ if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) {
+ stats->cacheSize += space;
+ }
+ }
+ } else {
+ long projectId = get_project_id(uid, PROJECT_ID_APP_START);
+ if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
+ stats->dataSize += space;
+ }
+ projectId = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
+ if ((space = GetOccupiedSpaceForProjectId(uuid, projectId)) != -1) {
stats->cacheSize += space;
+ stats->dataSize += space;
}
}
@@ -1588,47 +2202,6 @@
}
}
}
-
- if (extStats != nullptr) {
- static const bool supportsSdCardFs = supports_sdcardfs();
- space = get_occupied_app_space_external(uuid, userId, appId);
-
- if (space != -1) {
- extStats->dataSize += space;
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, if internal and external are on
- // the same volume, a uid such as u0_a123 is used for
- // application dirs on both internal and external storage;
- // therefore, substract that amount from internal to make sure
- // we don't count it double.
- stats->dataSize -= space;
- }
- }
-
- space = get_occupied_app_cache_space_external(uuid, userId, appId);
- if (space != -1) {
- extStats->dataSize += space; // cache counts for "data"
- extStats->cacheSize += space;
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, if internal and external are on
- // the same volume, a uid such as u0_a123 is used for both
- // internal and external storage; therefore, substract that
- // amount from internal to make sure we don't count it double.
- stats->dataSize -= space;
- }
- }
-
- if (!supportsSdCardFs && stats != nullptr) {
- // On devices without sdcardfs, the UID of OBBs on external storage
- // matches the regular app UID (eg u0_a123); therefore, to avoid
- // OBBs being include in stats->dataSize, compute the OBB size for
- // this app, and substract it from the size reported on internal
- // storage
- long obbProjectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START;
- int64_t appObbSize = GetOccupiedSpaceForProjectId(uuid, obbProjectId);
- stats->dataSize -= appObbSize;
- }
- }
}
static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1681,8 +2254,17 @@
closedir(d);
}
+void collectManualStatsForSubDirectories(const std::string& path, struct stats* stats) {
+ const auto subDirHandler = [&path, &stats](const std::string& subDir) {
+ auto fullpath = path + "/" + subDir;
+ collectManualStats(fullpath, stats);
+ };
+ foreach_subdir(path, subDirHandler);
+}
+
static void collectManualStatsForUser(const std::string& path, struct stats* stats,
- bool exclude_apps = false) {
+ bool exclude_apps = false,
+ bool is_sdk_sandbox_storage = false) {
DIR *d;
int dfd;
struct dirent *de;
@@ -1707,6 +2289,11 @@
continue;
} else if (exclude_apps && (user_uid >= AID_APP_START && user_uid <= AID_APP_END)) {
continue;
+ } else if (is_sdk_sandbox_storage) {
+ // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+ // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+ collectManualStatsForSubDirectories(StringPrintf("%s/%s", path.c_str(), name),
+ stats);
} else {
collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
}
@@ -1749,6 +2336,11 @@
fts_close(fts);
}
static bool ownsExternalStorage(int32_t appId) {
+ // if project id calculation is supported then, there is no need to
+ // calculate in a different way and project_id based calculation can work
+ if (internal_storage_has_project_id()) {
+ return false;
+ }
// Fetch external storage owner appid and check if it is the same as the
// current appId whose size is calculated
struct stat s;
@@ -1849,6 +2441,19 @@
collectManualStats(dePath, &stats);
ATRACE_END();
+ // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>),
+ // collect individual stats of each subdirectory (shared, storage of each sdk etc.)
+ if (appId >= AID_APP_START && appId <= AID_APP_END) {
+ ATRACE_BEGIN("sdksandbox");
+ auto sdkSandboxCePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname);
+ collectManualStatsForSubDirectories(sdkSandboxCePath, &stats);
+ auto sdkSandboxDePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname);
+ collectManualStatsForSubDirectories(sdkSandboxDePath, &stats);
+ ATRACE_END();
+ }
+
if (!uuid) {
ATRACE_BEGIN("profiles");
calculate_tree_size(
@@ -2085,6 +2690,13 @@
collectManualStatsForUser(dePath, &stats);
ATRACE_END();
+ ATRACE_BEGIN("sdksandbox");
+ auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId);
+ collectManualStatsForUser(sdkSandboxCePath, &stats, false, true);
+ auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId);
+ collectManualStatsForUser(sdkSandboxDePath, &stats, false, true);
+ ATRACE_END();
+
if (!uuid) {
ATRACE_BEGIN("profile");
auto userProfilePath = create_primary_cur_profile_dir_path(userId);
@@ -2251,7 +2863,7 @@
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
}
#ifdef ENABLE_STORAGE_CRATES
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
auto retVector = std::vector<std::optional<CrateMetadata>>();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
@@ -2297,7 +2909,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
#ifdef ENABLE_STORAGE_CRATES
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
auto retVector = std::vector<std::optional<CrateMetadata>>();
@@ -2354,7 +2966,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(codePath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
*_aidl_return = dump_profiles(uid, packageName, profileName, codePath);
return ok();
@@ -2366,7 +2978,7 @@
bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
*_aidl_return = copy_system_profile(systemProfile, packageUid, packageName, profileName);
return ok();
}
@@ -2376,7 +2988,7 @@
const std::string& profileName, int* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
*_aidl_return = analyze_primary_profiles(uid, packageName, profileName);
return ok();
@@ -2387,7 +2999,7 @@
const std::string& classpath, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
*_aidl_return = create_profile_snapshot(appId, packageName, profileName, classpath);
return ok();
@@ -2397,7 +3009,7 @@
const std::string& profileName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
std::string snapshot = create_snapshot_profile_path(packageName, profileName);
if ((unlink(snapshot.c_str()) != 0) && (errno != ENOENT)) {
@@ -2418,7 +3030,8 @@
const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
const std::optional<std::string>& profileName,
const std::optional<std::string>& dexMetadataPath,
- const std::optional<std::string>& compilationReason) {
+ const std::optional<std::string>& compilationReason,
+ bool* aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PATH(apkPath);
@@ -2427,7 +3040,8 @@
}
CHECK_ARGUMENT_PATH(outputPath);
CHECK_ARGUMENT_PATH(dexMetadataPath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ const auto userId = multiuser_get_user_id(uid);
+ LOCK_PACKAGE_USER();
const char* oat_dir = getCStr(outputPath);
const char* instruction_set = instructionSet.c_str();
@@ -2446,12 +3060,20 @@
const char* dm_path = getCStr(dexMetadataPath);
const char* compilation_reason = getCStr(compilationReason);
std::string error_msg;
+ bool completed = false; // not necessary but for compiler
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
- downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
+ downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg,
+ &completed);
+ *aidl_return = completed;
return res ? error(res, error_msg) : ok();
}
+binder::Status InstalldNativeService::controlDexOptBlocking(bool block) {
+ android::installd::control_dexopt_blocking(block);
+ return ok();
+}
+
binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
const std::string& packageName,
const std ::string& outDexFile, int uid,
@@ -2470,7 +3092,7 @@
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(nativeLibPath32);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -2561,7 +3183,16 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
+ return restoreconAppDataLocked(uuid, packageName, userId, flags, appId, seInfo);
+}
+
+binder::Status InstalldNativeService::restoreconAppDataLocked(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
binder::Status res = ok();
@@ -2587,11 +3218,54 @@
return res;
}
+binder::Status InstalldNativeService::restoreconSdkDataLocked(
+ const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+ binder::Status res = ok();
+
+ // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+ unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgName = packageName.c_str();
+ const char* seinfo = seInfo.c_str();
+
+ uid_t uid = multiuser_get_sdk_sandbox_uid(userId, appId);
+ constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE};
+ for (int currentFlag : storageFlags) {
+ if ((flags & currentFlag) == 0) {
+ continue;
+ }
+ const bool isCeData = (currentFlag == FLAG_STORAGE_CE);
+ const auto packagePath =
+ create_data_misc_sdk_sandbox_package_path(uuid_, isCeData, userId, pkgName);
+ if (access(packagePath.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << packagePath;
+ continue;
+ }
+ const auto subDirHandler = [&packagePath, &seinfo, &uid, &seflags,
+ &res](const std::string& subDir) {
+ const auto& fullpath = packagePath + "/" + subDir;
+ if (selinux_android_restorecon_pkgdir(fullpath.c_str(), seinfo, uid, seflags) < 0) {
+ res = error("restorecon failed for " + fullpath);
+ }
+ };
+ const auto ec = foreach_subdir(packagePath, subDirHandler);
+ if (ec != 0) {
+ res = error("Failed to restorecon for subdirs of " + packagePath);
+ }
+ }
+ return res;
+}
+
binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(oatDir);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
const char* oat_dir = oatDir.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -2616,7 +3290,7 @@
binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(packageDir);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
if (validate_apk_path(packageDir.c_str())) {
return error("Invalid path " + packageDir);
@@ -2632,7 +3306,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(fromBase);
CHECK_ARGUMENT_PATH(toBase);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
const char* relative_path = relativePath.c_str();
const char* from_base = fromBase.c_str();
@@ -2662,7 +3336,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(apkPath);
CHECK_ARGUMENT_PATH(outputPath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -2678,7 +3352,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PATH(apkPath);
CHECK_ARGUMENT_PATH(outputPath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE();
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -2688,142 +3362,6 @@
return *_aidl_return == -1 ? error() : ok();
}
-// This kernel feature is experimental.
-// TODO: remove local definition once upstreamed
-#ifndef FS_IOC_ENABLE_VERITY
-
-#define FS_IOC_ENABLE_VERITY _IO('f', 133)
-#define FS_IOC_SET_VERITY_MEASUREMENT _IOW('f', 134, struct fsverity_measurement)
-
-#define FS_VERITY_ALG_SHA256 1
-
-struct fsverity_measurement {
- __u16 digest_algorithm;
- __u16 digest_size;
- __u32 reserved1;
- __u64 reserved2[3];
- __u8 digest[];
-};
-
-#endif
-
-binder::Status InstalldNativeService::installApkVerity(const std::string& filePath,
- android::base::unique_fd verityInputAshmem, int32_t contentSize) {
- ENFORCE_UID(AID_SYSTEM);
- CHECK_ARGUMENT_PATH(filePath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
-
- if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
- return ok();
- }
-#ifndef NDEBUG
- ASSERT_PAGE_SIZE_4K();
-#endif
- // TODO: also check fsverity support in the current file system if compiled with DEBUG.
- // TODO: change ashmem to some temporary file to support huge apk.
- if (!ashmem_valid(verityInputAshmem.get())) {
- return error("FD is not an ashmem");
- }
-
- // 1. Seek to the next page boundary beyond the end of the file.
- ::android::base::unique_fd wfd(open(filePath.c_str(), O_WRONLY));
- if (wfd.get() < 0) {
- return error("Failed to open " + filePath);
- }
- struct stat st;
- if (fstat(wfd.get(), &st) < 0) {
- return error("Failed to stat " + filePath);
- }
- // fsverity starts from the block boundary.
- off_t padding = kVerityPageSize - st.st_size % kVerityPageSize;
- if (padding == kVerityPageSize) {
- padding = 0;
- }
- if (lseek(wfd.get(), st.st_size + padding, SEEK_SET) < 0) {
- return error("Failed to lseek " + filePath);
- }
-
- // 2. Write everything in the ashmem to the file. Note that allocated
- // ashmem size is multiple of page size, which is different from the
- // actual content size.
- int shmSize = ashmem_get_size_region(verityInputAshmem.get());
- if (shmSize < 0) {
- return error("Failed to get ashmem size: " + std::to_string(shmSize));
- }
- if (contentSize < 0) {
- return error("Invalid content size: " + std::to_string(contentSize));
- }
- if (contentSize > shmSize) {
- return error("Content size overflow: " + std::to_string(contentSize) + " > " +
- std::to_string(shmSize));
- }
- auto data = std::unique_ptr<void, std::function<void (void *)>>(
- mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
- [contentSize] (void* ptr) {
- if (ptr != MAP_FAILED) {
- munmap(ptr, contentSize);
- }
- });
-
- if (data.get() == MAP_FAILED) {
- return error("Failed to mmap the ashmem");
- }
- char* cursor = reinterpret_cast<char*>(data.get());
- int remaining = contentSize;
- while (remaining > 0) {
- int ret = TEMP_FAILURE_RETRY(write(wfd.get(), cursor, remaining));
- if (ret < 0) {
- return error("Failed to write to " + filePath + " (" + std::to_string(remaining) +
- + "/" + std::to_string(contentSize) + ")");
- }
- cursor += ret;
- remaining -= ret;
- }
- wfd.reset();
-
- // 3. Enable fsverity (needs readonly fd. Once it's done, the file becomes immutable.
- ::android::base::unique_fd rfd(open(filePath.c_str(), O_RDONLY));
- if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
- return error("Failed to enable fsverity on " + filePath);
- }
- return ok();
-}
-
-binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::string& filePath,
- const std::vector<uint8_t>& expectedHash) {
- ENFORCE_UID(AID_SYSTEM);
- CHECK_ARGUMENT_PATH(filePath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
-
- if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
- return ok();
- }
- // TODO: also check fsverity support in the current file system if compiled with DEBUG.
- if (expectedHash.size() != kSha256Size) {
- return error("verity hash size should be " + std::to_string(kSha256Size) + " but is " +
- std::to_string(expectedHash.size()));
- }
-
- ::android::base::unique_fd fd(open(filePath.c_str(), O_RDONLY));
- if (fd.get() < 0) {
- return error("Failed to open " + filePath + ": " + strerror(errno));
- }
-
- unsigned int buffer_size = sizeof(fsverity_measurement) + kSha256Size;
- std::vector<char> buffer(buffer_size, 0);
-
- fsverity_measurement* config = reinterpret_cast<fsverity_measurement*>(buffer.data());
- config->digest_algorithm = FS_VERITY_ALG_SHA256;
- config->digest_size = kSha256Size;
- memcpy(config->digest, expectedHash.data(), kSha256Size);
- if (ioctl(fd.get(), FS_IOC_SET_VERITY_MEASUREMENT, config) < 0) {
- // This includes an expected failure case with no FSVerity setup. It normally happens when
- // the apk does not contains the Merkle tree root hash.
- return error("Failed to measure fsverity on " + filePath + ": " + strerror(errno));
- }
- return ok(); // hashes match
-}
-
binder::Status InstalldNativeService::reconcileSecondaryDexFile(
const std::string& dexPath, const std::string& packageName, int32_t uid,
const std::vector<std::string>& isas, const std::optional<std::string>& volumeUuid,
@@ -2832,7 +3370,8 @@
CHECK_ARGUMENT_UUID(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(dexPath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ const auto userId = multiuser_get_user_id(uid);
+ LOCK_PACKAGE_USER();
bool result = android::installd::reconcile_secondary_dex_file(
dexPath, packageName, uid, isas, volumeUuid, storage_flag, _aidl_return);
@@ -2856,6 +3395,33 @@
return result ? ok() : error();
}
+bool check_if_ioctl_feature_is_supported() {
+ bool result = false;
+ auto temp_path = StringPrintf("%smisc/installd/ioctl_check", android_data_dir.c_str());
+ if (access(temp_path.c_str(), F_OK) != 0) {
+ open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+ result = set_quota_project_id(temp_path, 0, false) == 0;
+ // delete the temp file
+ // remove the external file
+ remove(temp_path.c_str());
+ }
+ return result;
+}
+
+binder::Status InstalldNativeService::setFirstBoot() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+ std::string uuid;
+ if (GetOccupiedSpaceForProjectId(uuid, 0) != -1 && check_if_ioctl_feature_is_supported()) {
+ auto first_boot_path =
+ StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+ if (access(first_boot_path.c_str(), F_OK) != 0) {
+ open(first_boot_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+ }
+ }
+ return ok();
+}
+
binder::Status InstalldNativeService::invalidateMounts() {
ENFORCE_UID(AID_SYSTEM);
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -2912,8 +3478,9 @@
const char* uuid_ = uuid->c_str();
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
- std::lock_guard<std::recursive_mutex> lock(mLock);
if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
return error("Failed to create CE mirror");
}
@@ -2982,8 +3549,9 @@
std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+ std::lock_guard<std::recursive_mutex> lock(mMountsLock);
+
// Unmount CE storage
- std::lock_guard<std::recursive_mutex> lock(mLock);
if (TEMP_FAILURE_RETRY(umount(mirrorCeVolPath.c_str())) != 0) {
if (errno != ENOENT) {
res = error(StringPrintf("Failed to umount %s %s", mirrorCeVolPath.c_str(),
@@ -3032,7 +3600,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
CHECK_ARGUMENT_PATH(codePath);
- std::lock_guard<std::recursive_mutex> lock(mLock);
+ LOCK_PACKAGE_USER();
*_aidl_return = prepare_app_profile(packageName, userId, appId, profileName, codePath,
dexMetadata);
@@ -3050,5 +3618,28 @@
return ok();
}
+binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
+ const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+ const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
+
+ if (flags & FLAG_STORAGE_CE) {
+ auto ce_path = create_data_user_ce_path(uuid_cstr, userId);
+ cleanup_invalid_package_dirs_under_path(ce_path);
+ auto sdksandbox_ce_path =
+ create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/true, userId);
+ cleanup_invalid_package_dirs_under_path(sdksandbox_ce_path);
+ }
+
+ if (flags & FLAG_STORAGE_DE) {
+ auto de_path = create_data_user_de_path(uuid_cstr, userId);
+ cleanup_invalid_package_dirs_under_path(de_path);
+ auto sdksandbox_de_path =
+ create_data_misc_sdk_sandbox_path(uuid_cstr, /*isCeData=*/false, userId);
+ cleanup_invalid_package_dirs_under_path(sdksandbox_de_path);
+ }
+
+ return ok();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index ea0c945..95ac516 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -21,8 +21,9 @@
#include <inttypes.h>
#include <unistd.h>
-#include <vector>
+#include <shared_mutex>
#include <unordered_map>
+#include <vector>
#include <android-base/macros.h>
#include <binder/BinderService.h>
@@ -46,8 +47,9 @@
int32_t flags);
binder::Status createAppData(const std::optional<std::string>& uuid,
- const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
- const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return);
+ const std::string& packageName, int32_t userId, int32_t flags,
+ int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int32_t targetSdkVersion, int64_t* _aidl_return);
binder::Status createAppData(
const android::os::CreateAppDataArgs& args,
@@ -56,9 +58,12 @@
const std::vector<android::os::CreateAppDataArgs>& args,
std::vector<android::os::CreateAppDataResult>* _aidl_return);
+ binder::Status reconcileSdkData(const android::os::ReconcileSdkDataArgs& args);
+
binder::Status restoreconAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo);
+
binder::Status migrateAppData(const std::optional<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags);
binder::Status clearAppData(const std::optional<std::string>& uuid,
@@ -117,7 +122,10 @@
const std::optional<std::string>& seInfo, bool downgrade,
int32_t targetSdkVersion, const std::optional<std::string>& profileName,
const std::optional<std::string>& dexMetadataPath,
- const std::optional<std::string>& compilationReason);
+ const std::optional<std::string>& compilationReason,
+ bool* aidl_return);
+
+ binder::Status controlDexOptBlocking(bool block);
binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
const std::string& outDexFile, int uid, bool* _aidl_return);
@@ -151,10 +159,6 @@
const std::string& outputPath);
binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
const std::optional<std::string>& outputPath, int64_t* _aidl_return);
- binder::Status installApkVerity(const std::string& filePath,
- android::base::unique_fd verityInput, int32_t contentSize);
- binder::Status assertFsverityRootHashMatches(const std::string& filePath,
- const std::vector<uint8_t>& expectedHash);
binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
const std::optional<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
@@ -163,6 +167,7 @@
int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
binder::Status invalidateMounts();
+ binder::Status setFirstBoot();
binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
bool* _aidl_return);
binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
@@ -175,8 +180,13 @@
binder::Status migrateLegacyObbData();
+ binder::Status cleanupInvalidPackageDirs(const std::optional<std::string>& uuid, int32_t userId,
+ int32_t flags);
+
private:
std::recursive_mutex mLock;
+ std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock;
+ std::unordered_map<std::string, std::weak_ptr<std::recursive_mutex>> mPackageNameLock;
std::recursive_mutex mMountsLock;
std::recursive_mutex mQuotasLock;
@@ -188,6 +198,34 @@
std::unordered_map<uid_t, int64_t> mCacheQuotas;
std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid);
+
+ binder::Status createAppDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, int32_t previousAppId,
+ const std::string& seInfo, int32_t targetSdkVersion,
+ int64_t* _aidl_return);
+ binder::Status restoreconAppDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo);
+
+ binder::Status createSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t appId,
+ int32_t flags);
+ binder::Status clearSdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t flags);
+ binder::Status destroySdkSandboxDataPackageDirectory(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ int32_t userId, int32_t flags);
+ binder::Status reconcileSdkData(const std::optional<std::string>& uuid,
+ const std::string& packageName,
+ const std::vector<std::string>& subDirNames, int32_t userId,
+ int32_t appId, int32_t previousAppId, const std::string& seInfo,
+ int flags);
+ binder::Status restoreconSdkDataLocked(const std::optional<std::string>& uuid,
+ const std::string& packageName, int32_t userId,
+ int32_t flags, int32_t appId, const std::string& seInfo);
};
} // namespace installd
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index d6807ff..643b2c2 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -4,7 +4,6 @@
jsharkey@android.com
maco@google.com
mast@google.com
-mathieuc@google.com
narayan@google.com
ngeoffray@google.com
rpl@google.com
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3f0fb6d..8ccab4c 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -30,6 +30,9 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "SdkSandboxStorageHostTest"
}
]
}
diff --git a/cmds/installd/binder/android/os/CreateAppDataArgs.aidl b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
index 96d7faa..d5e8ee5 100644
--- a/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
+++ b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
@@ -23,6 +23,7 @@
int userId;
int flags;
int appId;
+ int previousAppId;
@utf8InCpp String seInfo;
int targetSdkVersion;
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 3d32f61..c17c6bf 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -20,10 +20,12 @@
interface IInstalld {
void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
-
+ void setFirstBoot();
android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
+ void reconcileSdkData(in android.os.ReconcileSdkDataArgs args);
+
void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, int flags, int appId, @utf8InCpp String seInfo);
void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
@@ -55,7 +57,8 @@
@utf8InCpp String packageName, int appId,
@utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath);
- void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
+ // Returns false if it is cancelled. Returns true if it is completed or have other errors.
+ boolean dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
@utf8InCpp String instructionSet, int dexoptNeeded,
@nullable @utf8InCpp String outputPath, int dexFlags,
@utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
@@ -64,6 +67,9 @@
@nullable @utf8InCpp String profileName,
@nullable @utf8InCpp String dexMetadataPath,
@nullable @utf8InCpp String compilationReason);
+ // Blocks (when block is true) or unblock (when block is false) dexopt.
+ // Blocking also invloves cancelling the currently running dexopt.
+ void controlDexOptBlocking(boolean block);
boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
@utf8InCpp String outDexFile, int uid);
@@ -93,9 +99,6 @@
@utf8InCpp String outputPath);
long deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@nullable @utf8InCpp String outputPath);
- void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput,
- int contentSize);
- void assertFsverityRootHashMatches(@utf8InCpp String filePath, in byte[] expectedHash);
boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
@@ -125,9 +128,12 @@
void migrateLegacyObbData();
+ void cleanupInvalidPackageDirs(@nullable @utf8InCpp String uuid, int userId, int flags);
+
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
const int FLAG_STORAGE_EXTERNAL = 0x4;
+ const int FLAG_STORAGE_SDK = 0x8;
const int FLAG_CLEAR_CACHE_ONLY = 0x10;
const int FLAG_CLEAR_CODE_CACHE_ONLY = 0x20;
diff --git a/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
new file mode 100644
index 0000000..583a36d
--- /dev/null
+++ b/cmds/installd/binder/android/os/ReconcileSdkDataArgs.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+parcelable ReconcileSdkDataArgs {
+ @nullable @utf8InCpp String uuid;
+ @utf8InCpp String packageName;
+ @utf8InCpp List<String> subDirNames;
+ int userId;
+ int appId;
+ int previousAppId;
+ @utf8InCpp String seInfo;
+ int flags;
+}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index d678281..9647865 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -15,8 +15,8 @@
*/
#define LOG_TAG "installd"
-#include <array>
#include <fcntl.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
@@ -28,10 +28,14 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <array>
#include <iomanip>
+#include <mutex>
+#include <unordered_set>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/no_destructor.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -47,14 +51,17 @@
#include <selinux/android.h>
#include <server_configurable_flags/get_flags.h>
#include <system/thread_defs.h>
+#include <utils/Mutex.h>
+#include <ziparchive/zip_archive.h>
#include "dexopt.h"
#include "dexopt_return_codes.h"
#include "execv_helper.h"
#include "globals.h"
-#include "installd_deps.h"
#include "installd_constants.h"
+#include "installd_deps.h"
#include "otapreopt_utils.h"
+#include "restorable_file.h"
#include "run_dex2oat.h"
#include "unique_file.h"
#include "utils.h"
@@ -67,8 +74,87 @@
using android::base::ReadFully;
using android::base::StringPrintf;
using android::base::WriteFully;
+using android::base::borrowed_fd;
using android::base::unique_fd;
+namespace {
+
+// Timeout for short operations, such as merging profiles.
+constexpr int kShortTimeoutMs = 60000; // 1 minute.
+
+// Timeout for long operations, such as compilation. This should be smaller than the Package Manager
+// watchdog (PackageManagerService.WATCHDOG_TIMEOUT, 10 minutes), so that the operation will be
+// aborted before that watchdog would take down the system server.
+constexpr int kLongTimeoutMs = 570000; // 9.5 minutes.
+
+class DexOptStatus {
+ public:
+ // Check if dexopt is cancelled and fork if it is not cancelled.
+ // cancelled is set to true if cancelled. Otherwise it will be set to false.
+ // If it is not cancelled, it will return the return value of fork() call.
+ // If cancelled, fork will not happen and it will return -1.
+ pid_t check_cancellation_and_fork(/* out */ bool *cancelled) {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ if (dexopt_blocked_) {
+ *cancelled = true;
+ return -1;
+ }
+ pid_t pid = fork();
+ *cancelled = false;
+ if (pid > 0) { // parent
+ dexopt_pids_.insert(pid);
+ }
+ return pid;
+ }
+
+ // Returns true if pid was killed (is in killed list). It could have finished if killing
+ // happened after the process is finished.
+ bool check_if_killed_and_remove_dexopt_pid(pid_t pid) {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ dexopt_pids_.erase(pid);
+ if (dexopt_killed_pids_.erase(pid) == 1) {
+ return true;
+ }
+ return false;
+ }
+
+ // Tells whether dexopt is blocked or not.
+ bool is_dexopt_blocked() {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ return dexopt_blocked_;
+ }
+
+ // Enable or disable dexopt blocking.
+ void control_dexopt_blocking(bool block) {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ dexopt_blocked_ = block;
+ if (!block) {
+ return;
+ }
+ // Blocked, also kill currently running tasks
+ for (auto pid : dexopt_pids_) {
+ LOG(INFO) << "control_dexopt_blocking kill pid:" << pid;
+ kill(pid, SIGKILL);
+ dexopt_killed_pids_.insert(pid);
+ }
+ dexopt_pids_.clear();
+ }
+
+ private:
+ std::mutex dexopt_lock_;
+ // when true, dexopt is blocked and will not run.
+ bool dexopt_blocked_ GUARDED_BY(dexopt_lock_) = false;
+ // PIDs of child process while runinng dexopt.
+ // If the child process is finished, it should be removed.
+ std::unordered_set<pid_t> dexopt_pids_ GUARDED_BY(dexopt_lock_);
+ // PIDs of child processes killed by cancellation.
+ std::unordered_set<pid_t> dexopt_killed_pids_ GUARDED_BY(dexopt_lock_);
+};
+
+android::base::NoDestructor<DexOptStatus> dexopt_status_;
+
+} // namespace
+
namespace android {
namespace installd {
@@ -167,7 +253,7 @@
// The location is the profile name for primary apks or the dex path for secondary dex files.
bool clear_primary_current_profiles(const std::string& package_name, const std::string& location) {
bool success = true;
- // For secondary dex files, we don't really need the user but we use it for sanity checks.
+ // For secondary dex files, we don't really need the user but we use it for validity checks.
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
success &= clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
@@ -233,12 +319,6 @@
return profile_boot_class_path == "true";
}
-static void UnlinkIgnoreResult(const std::string& path) {
- if (unlink(path.c_str()) < 0) {
- PLOG(ERROR) << "Failed to unlink " << path;
- }
-}
-
/*
* Whether dexopt should use a swap file when compiling an APK.
*
@@ -384,8 +464,8 @@
});
}
-static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
- const std::string& location) {
+static unique_fd open_snapshot_profile(uid_t uid, const std::string& package_name,
+ const std::string& location) {
std::string profile = create_snapshot_profile_path(package_name, location);
return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
}
@@ -397,7 +477,7 @@
*reference_profile_fd = open_reference_profile(uid, package_name, location,
/*read_write*/ true, is_secondary_dex);
- // For secondary dex files, we don't really need the user but we use it for sanity checks.
+ // For secondary dex files, we don't really need the user but we use it for validity checks.
// Note: the user owning the dex file should be the current user.
std::vector<userid_t> users;
if (is_secondary_dex){
@@ -415,6 +495,25 @@
}
}
+// Cleans up an output file specified by a file descriptor. This function should be called whenever
+// a subprocess that modifies a system-managed file crashes.
+// If the subprocess crashes while it's writing to the file, the file is likely corrupted, so we
+// should remove it.
+// If the subprocess times out and is killed while it's acquiring a flock on the file, there is
+// probably a deadlock, so it's also good to remove the file so that later operations won't
+// encounter the same problem. It's safe to do so because the process that is holding the flock will
+// still have access to the file until the file descriptor is closed.
+// Note that we can't do `clear_reference_profile` here even if the fd points to a reference profile
+// because that also requires a flock and is therefore likely to be stuck in the second case.
+static bool cleanup_output_fd(int fd) {
+ std::string path;
+ bool ret = remove_file_at_fd(fd, &path);
+ if (ret) {
+ LOG(INFO) << "Removed file at path " << path;
+ }
+ return ret;
+}
+
static constexpr int PROFMAN_BIN_RETURN_CODE_SUCCESS = 0;
static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 1;
static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA = 2;
@@ -426,13 +525,14 @@
class RunProfman : public ExecVHelper {
public:
- void SetupArgs(const std::vector<unique_fd>& profile_fds,
- const unique_fd& reference_profile_fd,
- const std::vector<unique_fd>& apk_fds,
- const std::vector<std::string>& dex_locations,
- bool copy_and_update,
- bool for_snapshot,
- bool for_boot_image) {
+ template <typename T, typename U>
+ void SetupArgs(const std::vector<T>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<U>& apk_fds,
+ const std::vector<std::string>& dex_locations,
+ bool copy_and_update,
+ bool for_snapshot,
+ bool for_boot_image) {
// TODO(calin): Assume for now we run in the bg compile job (which is in
// most of the invocation). With the current data flow, is not very easy or
@@ -448,11 +548,11 @@
AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
}
- for (const unique_fd& fd : profile_fds) {
+ for (const T& fd : profile_fds) {
AddArg("--profile-file-fd=" + std::to_string(fd.get()));
}
- for (const unique_fd& fd : apk_fds) {
+ for (const U& fd : apk_fds) {
AddArg("--apk-fd=" + std::to_string(fd.get()));
}
@@ -511,20 +611,14 @@
for_boot_image);
}
- void SetupCopyAndUpdate(unique_fd&& profile_fd,
- unique_fd&& reference_profile_fd,
- unique_fd&& apk_fd,
+ void SetupCopyAndUpdate(const unique_fd& profile_fd,
+ const unique_fd& reference_profile_fd,
+ const unique_fd& apk_fd,
const std::string& dex_location) {
- // The fds need to stay open longer than the scope of the function, so put them into a local
- // variable vector.
- profiles_fd_.push_back(std::move(profile_fd));
- apk_fds_.push_back(std::move(apk_fd));
- reference_profile_fd_ = std::move(reference_profile_fd);
- std::vector<std::string> dex_locations = {dex_location};
- SetupArgs(profiles_fd_,
- reference_profile_fd_,
- apk_fds_,
- dex_locations,
+ SetupArgs(std::vector<borrowed_fd>{profile_fd},
+ reference_profile_fd,
+ std::vector<borrowed_fd>{apk_fd},
+ {dex_location},
/*copy_and_update=*/true,
/*for_snapshot*/false,
/*for_boot_image*/false);
@@ -550,11 +644,6 @@
void Exec() {
ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
}
-
- private:
- unique_fd reference_profile_fd_;
- std::vector<unique_fd> profiles_fd_;
- std::vector<unique_fd> apk_fds_;
};
static int analyze_profiles(uid_t uid, const std::string& package_name,
@@ -586,13 +675,14 @@
profman_merge.Exec();
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
bool need_to_compile = false;
bool empty_profiles = false;
bool should_clear_current_profiles = false;
bool should_clear_reference_profile = false;
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "profman failed for location " << location << ": " << return_code;
+ cleanup_output_fd(reference_profile_fd.get());
} else {
return_code = WEXITSTATUS(return_code);
switch (return_code) {
@@ -726,10 +816,10 @@
profman_dump.Exec();
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
- LOG(WARNING) << "profman failed for package " << pkgname << ": "
- << return_code;
+ LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
+ cleanup_output_fd(output_fd.get());
return false;
}
return true;
@@ -800,7 +890,11 @@
_exit(0);
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
+ if (!WIFEXITED(return_code)) {
+ cleanup_output_fd(out_fd.get());
+ return false;
+ }
return return_code == 0;
}
@@ -912,42 +1006,34 @@
}
// (re)Creates the app image if needed.
-UniqueFile maybe_open_app_image(const std::string& out_oat_path,
- bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) {
-
+RestorableFile maybe_open_app_image(const std::string& out_oat_path, bool generate_app_image,
+ bool is_public, int uid, bool is_secondary_dex) {
const std::string image_path = create_image_filename(out_oat_path);
if (image_path.empty()) {
// Happens when the out_oat_path has an unknown extension.
- return UniqueFile();
+ return RestorableFile();
}
- // In case there is a stale image, remove it now. Ignore any error.
- unlink(image_path.c_str());
-
// Not enabled, exit.
if (!generate_app_image) {
- return UniqueFile();
+ RestorableFile::RemoveAllFiles(image_path);
+ return RestorableFile();
}
std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
if (app_image_format.empty()) {
- return UniqueFile();
+ RestorableFile::RemoveAllFiles(image_path);
+ return RestorableFile();
}
- // Recreate is true since we do not want to modify a mapped image. If the app is
- // already running and we modify the image file, it can cause crashes (b/27493510).
- UniqueFile image_file(
- open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
- image_path,
- UnlinkIgnoreResult);
+ // If the app is already running and we modify the image file, it can cause crashes
+ // (b/27493510).
+ RestorableFile image_file = RestorableFile::CreateWritableFile(image_path,
+ /*permissions*/ 0600);
if (image_file.fd() < 0) {
// Could not create application image file. Go on since we can compile without it.
LOG(ERROR) << "installd could not create '" << image_path
<< "' for image file during dexopt";
- // If we have a valid image file path but no image fd, explicitly erase the image file.
- if (unlink(image_path.c_str()) < 0) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "Couldn't unlink image file " << image_path;
- }
- }
+ // If we have a valid image file path but cannot create tmp file, reset it.
+ image_file.reset();
} else if (!set_permissions_and_ownership(
image_file.fd(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
@@ -1021,9 +1107,9 @@
// Opens the vdex files and assigns the input fd to in_vdex_wrapper and the output fd to
// out_vdex_wrapper. Returns true for success or false in case of errors.
bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path, int dexopt_needed,
- const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
- bool profile_guided, UniqueFile* in_vdex_wrapper,
- UniqueFile* out_vdex_wrapper) {
+ const char* instruction_set, bool is_public, int uid,
+ bool is_secondary_dex, bool profile_guided,
+ UniqueFile* in_vdex_wrapper, RestorableFile* out_vdex_wrapper) {
CHECK(in_vdex_wrapper != nullptr);
CHECK(out_vdex_wrapper != nullptr);
// Open the existing VDEX. We do this before creating the new output VDEX, which will
@@ -1038,6 +1124,14 @@
return false;
}
+ // Create work file first. All files will be deleted when it fails.
+ *out_vdex_wrapper = RestorableFile::CreateWritableFile(out_vdex_path_str,
+ /*permissions*/ 0644);
+ if (out_vdex_wrapper->fd() < 0) {
+ ALOGE("installd cannot open vdex '%s' during dexopt\n", out_vdex_path_str.c_str());
+ return false;
+ }
+
bool update_vdex_in_place = false;
if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
// Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
@@ -1069,41 +1163,19 @@
(dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) &&
!profile_guided;
if (update_vdex_in_place) {
+ // dex2oat marks it invalid anyway. So delete it and set work file fd.
+ unlink(in_vdex_path_str.c_str());
// Open the file read-write to be able to update it.
- in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0),
- in_vdex_path_str);
- if (in_vdex_wrapper->fd() == -1) {
- // If we failed to open the file, we cannot update it in place.
- update_vdex_in_place = false;
- }
+ in_vdex_wrapper->reset(out_vdex_wrapper->fd(), in_vdex_path_str);
+ // Disable auto close for the in wrapper fd (it will be done when destructing the out
+ // wrapper).
+ in_vdex_wrapper->DisableAutoClose();
} else {
in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0),
in_vdex_path_str);
}
}
- // If we are updating the vdex in place, we do not need to recreate a vdex,
- // and can use the same existing one.
- if (update_vdex_in_place) {
- // We unlink the file in case the invocation of dex2oat fails, to ensure we don't
- // have bogus stale vdex files.
- out_vdex_wrapper->reset(
- in_vdex_wrapper->fd(),
- out_vdex_path_str,
- UnlinkIgnoreResult);
- // Disable auto close for the in wrapper fd (it will be done when destructing the out
- // wrapper).
- in_vdex_wrapper->DisableAutoClose();
- } else {
- out_vdex_wrapper->reset(
- open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
- out_vdex_path_str,
- UnlinkIgnoreResult);
- if (out_vdex_wrapper->fd() < 0) {
- ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
- return false;
- }
- }
if (!set_permissions_and_ownership(out_vdex_wrapper->fd(), is_public, uid,
out_vdex_path_str.c_str(), is_secondary_dex)) {
ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
@@ -1115,16 +1187,13 @@
}
// Opens the output oat file for the given apk.
-UniqueFile open_oat_out_file(const char* apk_path, const char* oat_dir,
- bool is_public, int uid, const char* instruction_set, bool is_secondary_dex) {
+RestorableFile open_oat_out_file(const char* apk_path, const char* oat_dir, bool is_public, int uid,
+ const char* instruction_set, bool is_secondary_dex) {
char out_oat_path[PKG_PATH_MAX];
if (!create_oat_out_path(apk_path, instruction_set, oat_dir, is_secondary_dex, out_oat_path)) {
- return UniqueFile();
+ return RestorableFile();
}
- UniqueFile oat(
- open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
- out_oat_path,
- UnlinkIgnoreResult);
+ RestorableFile oat = RestorableFile::CreateWritableFile(out_oat_path, /*permissions*/ 0644);
if (oat.fd() < 0) {
PLOG(ERROR) << "installd cannot open output during dexopt" << out_oat_path;
} else if (!set_permissions_and_ownership(
@@ -1475,7 +1544,7 @@
}
pipe_read.reset();
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
return false;
@@ -1525,23 +1594,46 @@
return ss.str();
}
+void control_dexopt_blocking(bool block) {
+ dexopt_status_->control_dexopt_blocking(block);
+}
+
+bool is_dexopt_blocked() {
+ return dexopt_status_->is_dexopt_blocked();
+}
+
+enum SecondaryDexOptProcessResult {
+ kSecondaryDexOptProcessOk = 0,
+ kSecondaryDexOptProcessCancelled = 1,
+ kSecondaryDexOptProcessError = 2
+};
+
// Processes the dex_path as a secondary dex files and return true if the path dex file should
-// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
-// successfully.
-// When returning true, the output parameters will be:
+// be compiled.
+// Returns: kSecondaryDexOptProcessError for errors (logged).
+// kSecondaryDexOptProcessOk if the secondary dex path was process successfully.
+// kSecondaryDexOptProcessCancelled if the processing was cancelled.
+//
+// When returning kSecondaryDexOptProcessOk, the output parameters will be:
// - is_public_out: whether or not the oat file should not be made public
// - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
// - oat_dir_out: the oat dir path where the oat file should be stored
-static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
- int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
- const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
- std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
- const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
+static SecondaryDexOptProcessResult process_secondary_dex_dexopt(const std::string& dex_path,
+ const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid,
+ const char* instruction_set, const char* compiler_filter, bool* is_public_out,
+ int* dexopt_needed_out, std::string* oat_dir_out, bool downgrade,
+ const char* class_loader_context, const std::vector<std::string>& context_dex_paths,
+ /* out */ std::string* error_msg) {
LOG(DEBUG) << "Processing secondary dex path " << dex_path;
+
+ if (dexopt_status_->is_dexopt_blocked()) {
+ return kSecondaryDexOptProcessCancelled;
+ }
+
int storage_flag;
if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
LOG(ERROR) << *error_msg;
- return false;
+ return kSecondaryDexOptProcessError;
}
// Compute the oat dir as it's not easy to extract it from the child computation.
char oat_path[PKG_PATH_MAX];
@@ -1550,11 +1642,15 @@
if (!create_secondary_dex_oat_layout(
dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
- return false;
+ return kSecondaryDexOptProcessError;
}
oat_dir_out->assign(oat_dir);
- pid_t pid = fork();
+ bool cancelled = false;
+ pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
+ if (cancelled) {
+ return kSecondaryDexOptProcessCancelled;
+ }
if (pid == 0) {
// child -- drop privileges before continuing.
drop_capabilities(uid);
@@ -1622,13 +1718,18 @@
}
/* parent */
- int result = wait_child(pid);
+ int result = wait_child_with_timeout(pid, kShortTimeoutMs);
+ cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
if (!WIFEXITED(result)) {
+ if ((WTERMSIG(result) == SIGKILL) && cancelled) {
+ LOG(INFO) << "dexoptanalyzer cancelled for path:" << dex_path;
+ return kSecondaryDexOptProcessCancelled;
+ }
*error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
dex_path.c_str(),
result);
LOG(ERROR) << *error_msg;
- return false;
+ return kSecondaryDexOptProcessError;
}
result = WEXITSTATUS(result);
// Check that we successfully executed dexoptanalyzer.
@@ -1656,7 +1757,7 @@
// It is ok to check this flag outside in the parent process.
*is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path);
- return success;
+ return success ? kSecondaryDexOptProcessOk : kSecondaryDexOptProcessError;
}
static std::string format_dexopt_error(int status, const char* dex_path) {
@@ -1670,17 +1771,29 @@
return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
}
+
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade, int target_sdk_version, const char* profile_name,
- const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
+ const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg,
+ /* out */ bool* completed) {
CHECK(pkgname != nullptr);
CHECK(pkgname[0] != 0);
CHECK(error_msg != nullptr);
CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0)
<< "dexopt flags contains unknown fields: " << dexopt_flags;
+ bool local_completed; // local placeholder for nullptr case
+ if (completed == nullptr) {
+ completed = &local_completed;
+ }
+ *completed = true;
+ if (dexopt_status_->is_dexopt_blocked()) {
+ *completed = false;
+ return 0;
+ }
+
if (!validate_dex_path_size(dex_path)) {
*error_msg = StringPrintf("Failed to validate %s", dex_path);
return -1;
@@ -1712,14 +1825,20 @@
*error_msg = "Failed acquiring context dex paths";
return -1; // We had an error, logged in the process method.
}
-
- if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
- instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
- downgrade, class_loader_context, context_dex_paths, error_msg)) {
+ SecondaryDexOptProcessResult sec_dex_result = process_secondary_dex_dexopt(dex_path,
+ pkgname, dexopt_flags, volume_uuid, uid,instruction_set, compiler_filter,
+ &is_public, &dexopt_needed, &oat_dir_str, downgrade, class_loader_context,
+ context_dex_paths, error_msg);
+ if (sec_dex_result == kSecondaryDexOptProcessOk) {
oat_dir = oat_dir_str.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
+ *completed = true;
return 0; // Nothing to do, report success.
}
+ } else if (sec_dex_result == kSecondaryDexOptProcessCancelled) {
+ // cancelled, not an error.
+ *completed = false;
+ return 0;
} else {
if (error_msg->empty()) { // TODO: Make this a CHECK.
*error_msg = "Failed processing secondary.";
@@ -1749,8 +1868,8 @@
}
// Create the output OAT file.
- UniqueFile out_oat = open_oat_out_file(dex_path, oat_dir, is_public, uid,
- instruction_set, is_secondary_dex);
+ RestorableFile out_oat =
+ open_oat_out_file(dex_path, oat_dir, is_public, uid, instruction_set, is_secondary_dex);
if (out_oat.fd() < 0) {
*error_msg = "Could not open out oat file.";
return -1;
@@ -1758,7 +1877,7 @@
// Open vdex files.
UniqueFile in_vdex;
- UniqueFile out_vdex;
+ RestorableFile out_vdex;
if (!open_vdex_files_for_dex2oat(dex_path, out_oat.path().c_str(), dexopt_needed,
instruction_set, is_public, uid, is_secondary_dex, profile_guided, &in_vdex,
&out_vdex)) {
@@ -1794,8 +1913,8 @@
}
// Create the app image file if needed.
- UniqueFile out_image = maybe_open_app_image(
- out_oat.path(), generate_app_image, is_public, uid, is_secondary_dex);
+ RestorableFile out_image = maybe_open_app_image(out_oat.path(), generate_app_image, is_public,
+ uid, is_secondary_dex);
UniqueFile dex_metadata;
if (dex_metadata_path != nullptr) {
@@ -1828,28 +1947,20 @@
LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
RunDex2Oat runner(dex2oat_bin, execv_helper.get());
- runner.Initialize(out_oat,
- out_vdex,
- out_image,
- in_dex,
- in_vdex,
- dex_metadata,
- reference_profile,
- class_loader_context,
- join_fds(context_input_fds),
- swap_fd.get(),
- instruction_set,
- compiler_filter,
- debuggable,
- boot_complete,
- for_restore,
- target_sdk_version,
- enable_hidden_api_checks,
- generate_compact_dex,
- use_jitzygote_image,
+ runner.Initialize(out_oat.GetUniqueFile(), out_vdex.GetUniqueFile(), out_image.GetUniqueFile(),
+ in_dex, in_vdex, dex_metadata, reference_profile, class_loader_context,
+ join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter,
+ debuggable, boot_complete, for_restore, target_sdk_version,
+ enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image,
compilation_reason);
- pid_t pid = fork();
+ bool cancelled = false;
+ pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
+ if (cancelled) {
+ *completed = false;
+ reference_profile.DisableCleanup();
+ return 0;
+ }
if (pid == 0) {
// Need to set schedpolicy before dropping privileges
// for cgroup migration. See details at b/175178520.
@@ -1866,10 +1977,18 @@
runner.Exec(DexoptReturnCodes::kDex2oatExec);
} else {
- int res = wait_child(pid);
+ int res = wait_child_with_timeout(pid, kLongTimeoutMs);
+ bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
if (res == 0) {
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
} else {
+ if ((WTERMSIG(res) == SIGKILL) && cancelled) {
+ LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- cancelled";
+ // cancelled, not an error
+ *completed = false;
+ reference_profile.DisableCleanup();
+ return 0;
+ }
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
<< std::hex << std::setw(4) << res << ", process failed";
*error_msg = format_dexopt_error(res, dex_path);
@@ -1877,12 +1996,43 @@
}
}
- // We've been successful, don't delete output.
- out_oat.DisableCleanup();
- out_vdex.DisableCleanup();
- out_image.DisableCleanup();
+ // dex2oat ran successfully, so profile is safe to keep.
reference_profile.DisableCleanup();
+ // We've been successful, commit work files.
+ // If committing (=renaming tmp to regular) fails, try to restore backup files.
+ // If restoring fails as well, as a last resort, remove all files.
+ if (!out_oat.CreateBackupFile() || !out_vdex.CreateBackupFile() ||
+ !out_image.CreateBackupFile()) {
+ // Renaming failure can mean that the original file may not be accessible from installd.
+ LOG(ERROR) << "Cannot create backup file from existing file, file in wrong state?"
+ << ", out_oat:" << out_oat.path() << " ,out_vdex:" << out_vdex.path()
+ << " ,out_image:" << out_image.path();
+ out_oat.ResetAndRemoveAllFiles();
+ out_vdex.ResetAndRemoveAllFiles();
+ out_image.ResetAndRemoveAllFiles();
+ return -1;
+ }
+ if (!out_oat.CommitWorkFile() || !out_vdex.CommitWorkFile() || !out_image.CommitWorkFile()) {
+ LOG(ERROR) << "Cannot commit, out_oat:" << out_oat.path()
+ << " ,out_vdex:" << out_vdex.path() << " ,out_image:" << out_image.path();
+ if (!out_oat.RestoreBackupFile() || !out_vdex.RestoreBackupFile() ||
+ !out_image.RestoreBackupFile()) {
+ LOG(ERROR) << "Cannot cancel commit, out_oat:" << out_oat.path()
+ << " ,out_vdex:" << out_vdex.path() << " ,out_image:" << out_image.path();
+ // Restoring failed.
+ out_oat.ResetAndRemoveAllFiles();
+ out_vdex.ResetAndRemoveAllFiles();
+ out_image.ResetAndRemoveAllFiles();
+ }
+ return -1;
+ }
+ // Now remove remaining backup files.
+ out_oat.RemoveBackupFile();
+ out_vdex.RemoveBackupFile();
+ out_image.RemoveBackupFile();
+
+ *completed = true;
return 0;
}
@@ -2016,7 +2166,7 @@
_exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
}
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "reconcile dex failed for location " << dex_path << ": " << return_code;
} else {
@@ -2134,7 +2284,7 @@
if (!ReadFully(pipe_read, out_secondary_dex_hash->data(), out_secondary_dex_hash->size())) {
out_secondary_dex_hash->clear();
}
- return wait_child(pid) == 0;
+ return wait_child_with_timeout(pid, kShortTimeoutMs) == 0;
}
// Helper for move_ab, so that we can have common failure-case cleanup.
@@ -2425,7 +2575,7 @@
const std::string& classpath) {
int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id);
- unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
+ unique_fd snapshot_fd = open_snapshot_profile(AID_SYSTEM, package_name, profile_name);
if (snapshot_fd < 0) {
return false;
}
@@ -2464,9 +2614,10 @@
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+ cleanup_output_fd(snapshot_fd.get());
return false;
}
@@ -2499,7 +2650,7 @@
}
// Open and create the snapshot profile.
- unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name);
+ unique_fd snapshot_fd = open_snapshot_profile(AID_SYSTEM, package_name, profile_name);
// Collect all non empty profiles.
// The collection will traverse all applications profiles and find the non empty files.
@@ -2573,10 +2724,11 @@
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+ cleanup_output_fd(snapshot_fd.get());
return false;
}
@@ -2601,6 +2753,20 @@
}
}
+static bool check_profile_exists_in_dexmetadata(const std::string& dex_metadata) {
+ ZipArchiveHandle zip = nullptr;
+ if (OpenArchive(dex_metadata.c_str(), &zip) != 0) {
+ PLOG(ERROR) << "Failed to open dm '" << dex_metadata << "'";
+ return false;
+ }
+
+ ZipEntry64 entry;
+ int result = FindEntry(zip, "primary.prof", &entry);
+ CloseArchive(zip);
+
+ return result != 0 ? false : true;
+}
+
bool prepare_app_profile(const std::string& package_name,
userid_t user_id,
appid_t app_id,
@@ -2617,7 +2783,7 @@
}
// Check if we need to install the profile from the dex metadata.
- if (!dex_metadata) {
+ if (!dex_metadata || !check_profile_exists_in_dexmetadata(dex_metadata->c_str())) {
return true;
}
@@ -2633,9 +2799,9 @@
}
RunProfman args;
- args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
- std::move(ref_profile_fd),
- std::move(apk_fd),
+ args.SetupCopyAndUpdate(dex_metadata_fd,
+ ref_profile_fd,
+ apk_fd,
code_path);
pid_t pid = fork();
if (pid == 0) {
@@ -2648,9 +2814,10 @@
}
/* parent */
- int return_code = wait_child(pid);
+ int return_code = wait_child_with_timeout(pid, kShortTimeoutMs);
if (!WIFEXITED(return_code)) {
PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name;
+ cleanup_output_fd(ref_profile_fd.get());
return false;
}
return true;
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5a637b1..12579b0 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -121,11 +121,18 @@
const std::string& pkgname, int uid, const std::optional<std::string>& volume_uuid,
int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash);
+// completed pass false if it is canceled. Otherwise it will be true even if there is other
+// error.
int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade, int target_sdk_version, const char* profile_name,
- const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg);
+ const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg,
+ /* out */ bool* completed = nullptr);
+
+bool is_dexopt_blocked();
+
+void control_dexopt_blocking(bool block);
bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 6aa32b8..e978e79 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -140,8 +140,8 @@
PrepareEnvironmentVariables();
- if (!EnsureBootImageAndDalvikCache()) {
- LOG(ERROR) << "Bad boot image.";
+ if (!EnsureDalvikCache()) {
+ LOG(ERROR) << "Bad dalvik cache.";
return 5;
}
@@ -349,8 +349,8 @@
}
}
- // Ensure that we have the right boot image and cache file structures.
- bool EnsureBootImageAndDalvikCache() const {
+ // Ensure that we have the right cache file structures.
+ bool EnsureDalvikCache() const {
if (parameters_.instruction_set == nullptr) {
LOG(ERROR) << "Instruction set missing.";
return false;
@@ -376,15 +376,6 @@
}
}
- // Check whether we have a boot image.
- // TODO: check that the files are correct wrt/ jars.
- std::string preopted_boot_art_path =
- StringPrintf("/apex/com.android.art/javalib/%s/boot.art", isa);
- if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
- PLOG(ERROR) << "Bad access() to " << preopted_boot_art_path;
- return false;
- }
-
return true;
}
diff --git a/cmds/installd/restorable_file.cpp b/cmds/installd/restorable_file.cpp
new file mode 100644
index 0000000..fd54a23
--- /dev/null
+++ b/cmds/installd/restorable_file.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 "restorable_file.h"
+
+#include <string>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+namespace {
+
+constexpr char kTmpFileSuffix[] = ".tmp";
+constexpr char kBackupFileSuffix[] = ".backup";
+
+std::string GetTmpFilePath(const std::string& path) {
+ return android::base::StringPrintf("%s%s", path.c_str(), kTmpFileSuffix);
+}
+
+std::string GetBackupFilePath(const std::string& path) {
+ return android::base::StringPrintf("%s%s", path.c_str(), kBackupFileSuffix);
+}
+
+void UnlinkPossiblyNonExistingFile(const std::string& path) {
+ if (unlink(path.c_str()) < 0) {
+ if (errno != ENOENT && errno != EROFS) { // EROFS reported even if it does not exist.
+ PLOG(ERROR) << "Cannot unlink: " << path;
+ }
+ }
+}
+
+// Check if file for the given path exists
+bool FileExists(const std::string& path) {
+ struct stat st;
+ return ::stat(path.c_str(), &st) == 0;
+}
+
+} // namespace
+
+namespace android {
+namespace installd {
+
+RestorableFile::RestorableFile() : RestorableFile(-1, "") {}
+
+RestorableFile::RestorableFile(int value, const std::string& path) : unique_file_(value, path) {
+ // As cleanup is null, this does not make much difference but use unique_file_ only for closing
+ // tmp file.
+ unique_file_.DisableCleanup();
+}
+
+RestorableFile::~RestorableFile() {
+ reset();
+}
+
+void RestorableFile::reset() {
+ // need to copy before reset clears it.
+ std::string path(unique_file_.path());
+ unique_file_.reset();
+ if (!path.empty()) {
+ UnlinkPossiblyNonExistingFile(GetTmpFilePath(path));
+ }
+}
+
+bool RestorableFile::CreateBackupFile() {
+ if (path().empty() || !FileExists(path())) {
+ return true;
+ }
+ std::string backup = GetBackupFilePath(path());
+ UnlinkPossiblyNonExistingFile(backup);
+ if (rename(path().c_str(), backup.c_str()) < 0) {
+ PLOG(ERROR) << "Cannot rename " << path() << " to " << backup;
+ return false;
+ }
+ return true;
+}
+
+bool RestorableFile::CommitWorkFile() {
+ std::string path(unique_file_.path());
+ // Keep the path with Commit for debugging purpose.
+ unique_file_.reset(-1, path);
+ if (!path.empty()) {
+ if (rename(GetTmpFilePath(path).c_str(), path.c_str()) < 0) {
+ PLOG(ERROR) << "Cannot rename " << GetTmpFilePath(path) << " to " << path;
+ // Remove both files as renaming can fail due to the original file as well.
+ UnlinkPossiblyNonExistingFile(path);
+ UnlinkPossiblyNonExistingFile(GetTmpFilePath(path));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool RestorableFile::RestoreBackupFile() {
+ std::string backup = GetBackupFilePath(path());
+ if (path().empty() || !FileExists(backup)) {
+ return true;
+ }
+ UnlinkPossiblyNonExistingFile(path());
+ if (rename(backup.c_str(), path().c_str()) < 0) {
+ PLOG(ERROR) << "Cannot rename " << backup << " to " << path();
+ return false;
+ }
+ return true;
+}
+
+void RestorableFile::RemoveBackupFile() {
+ UnlinkPossiblyNonExistingFile(GetBackupFilePath(path()));
+}
+
+const UniqueFile& RestorableFile::GetUniqueFile() const {
+ return unique_file_;
+}
+
+void RestorableFile::ResetAndRemoveAllFiles() {
+ std::string path(unique_file_.path());
+ reset();
+ RemoveAllFiles(path);
+}
+
+RestorableFile RestorableFile::CreateWritableFile(const std::string& path, int permissions) {
+ std::string tmp_file_path = GetTmpFilePath(path);
+ // If old tmp file exists, delete it.
+ UnlinkPossiblyNonExistingFile(tmp_file_path);
+ int fd = -1;
+ if (!path.empty()) {
+ fd = open(tmp_file_path.c_str(), O_RDWR | O_CREAT, permissions);
+ if (fd < 0) {
+ PLOG(ERROR) << "Cannot create file: " << tmp_file_path;
+ }
+ }
+ RestorableFile rf(fd, path);
+ return rf;
+}
+
+void RestorableFile::RemoveAllFiles(const std::string& path) {
+ UnlinkPossiblyNonExistingFile(GetTmpFilePath(path));
+ UnlinkPossiblyNonExistingFile(GetBackupFilePath(path));
+ UnlinkPossiblyNonExistingFile(path);
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/restorable_file.h b/cmds/installd/restorable_file.h
new file mode 100644
index 0000000..eda2292
--- /dev/null
+++ b/cmds/installd/restorable_file.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INSTALLD_RESTORABLE_FILE_H
+#define ANDROID_INSTALLD_RESTORABLE_FILE_H
+
+#include <functional>
+#include <string>
+
+#include "unique_file.h"
+
+namespace android {
+namespace installd {
+
+// This is a file abstraction which allows restoring to the original file while temporary work
+// file is updated.
+//
+// Typical flow for this API will be:
+// RestorableFile rf = RestorableFile::CreateWritableFile(...)
+// write to file using file descriptor acquired from: rf.fd()
+// Make work file into a regular file with: rf.CommitWorkFile()
+// Or throw away the work file by destroying the instance without calling CommitWorkFile().
+// The temporary work file is closed / removed when an instance is destroyed without calling
+// CommitWorkFile(). The original file, if CommitWorkFile() is not called, will be kept.
+//
+// For safer restoration of original file when commit fails, following 3 steps can be taken:
+// 1. CreateBackupFile(): This renames an existing regular file into a separate backup file.
+// 2. CommitWorkFile(): Rename the work file into the regular file.
+// 3. RemoveBackupFile(): Removes the backup file
+// If CommitWorkFile fails, client can call RestoreBackupFile() which will restore regular file from
+// the backup.
+class RestorableFile {
+public:
+ // Creates invalid instance with no fd (=-1) and empty path.
+ RestorableFile();
+ RestorableFile(RestorableFile&& other) = default;
+ ~RestorableFile();
+
+ // Passes all contents of other file into the current file.
+ // Files kept for the current file will be either deleted or committed depending on
+ // CommitWorkFile() and DisableCleanUp() calls made before this.
+ RestorableFile& operator=(RestorableFile&& other) = default;
+
+ // Gets file descriptor for backing work (=temporary) file. If work file does not exist, it will
+ // return -1.
+ int fd() const { return unique_file_.fd(); }
+
+ // Gets the path name for the regular file (not temporary file).
+ const std::string& path() const { return unique_file_.path(); }
+
+ // Closes work file, deletes it and resets all internal states into default states.
+ void reset();
+
+ // Closes work file and closes all files including work file, backup file and regular file.
+ void ResetAndRemoveAllFiles();
+
+ // Creates a backup file by renaming existing regular file. This will return false if renaming
+ // fails. If regular file for renaming does not exist, it will return true.
+ bool CreateBackupFile();
+
+ // Closes existing work file and makes it a regular file.
+ // Note that the work file is closed and fd() will return -1 after this. path() will still
+ // return the original path.
+ // This will return false when committing fails (=cannot rename). Both the regular file and tmp
+ // file will be deleted when it fails.
+ bool CommitWorkFile();
+
+ // Cancels the commit and restores the backup file into the regular one. If renaming fails,
+ // it will return false. This returns true if the backup file does not exist.
+ bool RestoreBackupFile();
+
+ // Removes the backup file.
+ void RemoveBackupFile();
+
+ // Gets UniqueFile with the same path and fd() pointing to the work file.
+ const UniqueFile& GetUniqueFile() const;
+
+ // Creates writable RestorableFile. This involves creating tmp file for writing.
+ static RestorableFile CreateWritableFile(const std::string& path, int permissions);
+
+ // Removes the specified file together with tmp file generated as RestorableFile.
+ static void RemoveAllFiles(const std::string& path);
+
+private:
+ RestorableFile(int value, const std::string& path);
+
+ // Used as a storage for work file fd and path string.
+ UniqueFile unique_file_;
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_RESTORABLE_FILE_H
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index b661684..51c4589 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -50,10 +50,6 @@
static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
-// Location of the JIT Zygote image.
-static const char* kJitZygoteImage =
- "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
-
std::vector<std::string> SplitBySpaces(const std::string& str) {
if (str.empty()) {
return {};
@@ -84,9 +80,9 @@
int target_sdk_version,
bool enable_hidden_api_checks,
bool generate_compact_dex,
- bool use_jitzygote_image,
+ bool use_jitzygote,
const char* compilation_reason) {
- PrepareBootImageFlags(use_jitzygote_image);
+ PrepareBootImageFlags(use_jitzygote);
PrepareInputFileFlags(output_oat, output_vdex, output_image, input_dex, input_vdex,
dex_metadata, profile, swap_fd, class_loader_context,
@@ -112,14 +108,14 @@
RunDex2Oat::~RunDex2Oat() {}
-void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote_image) {
- std::string boot_image;
- if (use_jitzygote_image) {
- boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
+void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote) {
+ if (use_jitzygote) {
+ // Don't pass a boot image because JIT Zygote should decide which image to use. Typically,
+ // it does not use any boot image on disk.
+ AddArg("--force-jit-zygote");
} else {
- boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
+ AddArg(MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s"));
}
- AddArg(boot_image);
}
void RunDex2Oat::PrepareInputFileFlags(const UniqueFile& output_oat,
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index 475e124..559244f 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -50,13 +50,13 @@
int target_sdk_version,
bool enable_hidden_api_checks,
bool generate_compact_dex,
- bool use_jitzygote_image,
+ bool use_jitzygote,
const char* compilation_reason);
void Exec(int exit_code);
protected:
- void PrepareBootImageFlags(bool use_jitzygote_image);
+ void PrepareBootImageFlags(bool use_jitzygote);
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 0a638cd..2a8135a 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -114,7 +114,7 @@
int target_sdk_version = 0;
bool enable_hidden_api_checks = false;
bool generate_compact_dex = true;
- bool use_jitzygote_image = false;
+ bool use_jitzygote = false;
const char* compilation_reason = nullptr;
};
@@ -175,6 +175,7 @@
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_["--boot-image"] = FLAG_UNUSED;
// Arch
default_expected_flags_["--instruction-set"] = "=arm64";
@@ -190,6 +191,7 @@
default_expected_flags_["--max-image-block-size"] = FLAG_UNUSED;
default_expected_flags_["--very-large-app-threshold"] = FLAG_UNUSED;
default_expected_flags_["--resolve-startup-const-strings"] = FLAG_UNUSED;
+ default_expected_flags_["--force-jit-zygote"] = FLAG_UNUSED;
// Debug
default_expected_flags_["--debuggable"] = FLAG_UNUSED;
@@ -256,7 +258,7 @@
args->target_sdk_version,
args->enable_hidden_api_checks,
args->generate_compact_dex,
- args->use_jitzygote_image,
+ args->use_jitzygote,
args->compilation_reason);
runner.Exec(/*exit_code=*/ 0);
}
@@ -557,5 +559,22 @@
VerifyExpectedFlags();
}
+TEST_F(RunDex2OatTest, UseJitZygoteImage) {
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->use_jitzygote = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("--force-jit-zygote", "");
+ VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, BootImage) {
+ setSystemProperty("dalvik.vm.boot-image", "foo.art:bar.art");
+ CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+ SetExpectedFlagUsed("--boot-image", "=foo.art:bar.art");
+ VerifyExpectedFlags();
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 024e3af..b3baca5 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -25,6 +25,8 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
+ "libgmock",
"libinstalld",
"liblog",
],
@@ -53,7 +55,9 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
+ "libziparchive",
"liblog",
"liblogwrap",
],
@@ -92,14 +96,18 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "packagemanager_aidl-cpp",
"server_configurable_flags",
],
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
+ "libziparchive",
"liblog",
"liblogwrap",
+ "libc++fs",
],
test_config: "installd_service_test.xml",
@@ -141,6 +149,7 @@
static_libs: [
"libasync_safe",
"libdiskusage",
+ "libext2_uuid",
"libinstalld",
"liblog",
"liblogwrap",
@@ -185,3 +194,24 @@
"libotapreoptparameters",
],
}
+
+cc_test {
+ name: "installd_file_test",
+ test_suites: ["device-tests"],
+ clang: true,
+ srcs: ["installd_file_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libutils",
+ ],
+ static_libs: [
+ "libext2_uuid",
+ "libinstalld",
+ "liblog",
+ ],
+}
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 863cdfe..72f5f4b 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -122,6 +122,7 @@
service = new InstalldNativeService();
testUuid = kTestUuid;
+ system("rm -rf /data/local/tmp/user");
system("mkdir -p /data/local/tmp/user/0");
}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 7e7e513..aeba451 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -50,6 +50,8 @@
namespace android {
namespace installd {
+constexpr int kTimeoutMs = 60000;
+
// TODO(calin): try to dedup this code.
#if defined(__arm__)
static const std::string kRuntimeIsa = "arm";
@@ -232,6 +234,7 @@
virtual void TearDown() {
if (!kDebug) {
+ service_->controlDexOptBlocking(false);
service_->destroyAppData(
volume_uuid_, package_name_, kTestUserId, kAppDataFlags, ce_data_inode_);
run_cmd("rm -rf " + app_apk_dir_);
@@ -286,6 +289,7 @@
kTestUserId,
kAppDataFlags,
kTestAppUid,
+ 0 /* previousAppId */,
se_info_,
kOSdkVersion,
&ce_data_inode_);
@@ -347,7 +351,7 @@
void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
bool should_binder_call_succeed, bool should_dex_be_compiled = true,
/*out */ binder::Status* binder_result = nullptr, int32_t uid = -1,
- const char* class_loader_context = nullptr) {
+ const char* class_loader_context = nullptr, bool expect_completed = true) {
if (uid == -1) {
uid = kTestAppUid;
}
@@ -364,6 +368,7 @@
std::optional<std::string> dm_path;
std::optional<std::string> compilation_reason;
+ bool completed = false;
binder::Status result = service_->dexopt(path,
uid,
package_name_,
@@ -379,8 +384,10 @@
target_sdk_version,
profile_name,
dm_path,
- compilation_reason);
+ compilation_reason,
+ &completed);
ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+ ASSERT_EQ(expect_completed, completed);
int expected_access = should_dex_be_compiled ? 0 : -1;
std::string odex = GetSecondaryDexArtifact(path, "odex");
std::string vdex = GetSecondaryDexArtifact(path, "vdex");
@@ -431,6 +438,11 @@
ASSERT_EQ(mode, st.st_mode);
}
+ void AssertNoFile(const std::string& file) {
+ struct stat st;
+ ASSERT_EQ(-1, stat(file.c_str(), &st));
+ }
+
void CompilePrimaryDexOk(std::string compiler_filter,
int32_t dex_flags,
const char* oat_dir,
@@ -447,6 +459,7 @@
dm_path,
downgrade,
true,
+ true,
binder_result);
}
@@ -466,6 +479,27 @@
dm_path,
downgrade,
false,
+ true,
+ binder_result);
+ }
+
+ void CompilePrimaryDexCancelled(std::string compiler_filter,
+ int32_t dex_flags,
+ const char* oat_dir,
+ int32_t uid,
+ int32_t dexopt_needed,
+ binder::Status* binder_result = nullptr,
+ const char* dm_path = nullptr,
+ bool downgrade = false) {
+ CompilePrimaryDex(compiler_filter,
+ dex_flags,
+ oat_dir,
+ uid,
+ dexopt_needed,
+ dm_path,
+ downgrade,
+ true, // should_binder_call_succeed
+ false, // expect_completed
binder_result);
}
@@ -477,6 +511,7 @@
const char* dm_path,
bool downgrade,
bool should_binder_call_succeed,
+ bool expect_completed,
/*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 = "PCL[]";
@@ -491,6 +526,7 @@
dm_path_opt, &prof_result));
ASSERT_TRUE(prof_result);
+ bool completed = false;
binder::Status result = service_->dexopt(apk_path_,
uid,
package_name_,
@@ -506,8 +542,10 @@
target_sdk_version,
profile_name,
dm_path_opt,
- compilation_reason);
+ compilation_reason,
+ &completed);
ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+ ASSERT_EQ(expect_completed, completed);
if (!should_binder_call_succeed) {
if (binder_result != nullptr) {
@@ -525,11 +563,20 @@
bool is_public = (dex_flags & DEXOPT_PUBLIC) != 0;
mode_t mode = S_IFREG | (is_public ? 0644 : 0640);
- CheckFileAccess(odex, kSystemUid, uid, mode);
- CheckFileAccess(vdex, kSystemUid, uid, mode);
+ if (expect_completed) {
+ CheckFileAccess(odex, kSystemUid, uid, mode);
+ CheckFileAccess(vdex, kSystemUid, uid, mode);
+ } else {
+ AssertNoFile(odex);
+ AssertNoFile(vdex);
+ }
if (compiler_filter == "speed-profile") {
- CheckFileAccess(art, kSystemUid, uid, mode);
+ if (expect_completed) {
+ CheckFileAccess(art, kSystemUid, uid, mode);
+ } else {
+ AssertNoFile(art);
+ }
}
if (binder_result != nullptr) {
*binder_result = result;
@@ -750,6 +797,28 @@
empty_dm_file_.c_str());
}
+TEST_F(DexoptTest, DexoptBlockPrimary) {
+ LOG(INFO) << "DexoptPrimaryPublic";
+ service_->controlDexOptBlocking(true);
+ CompilePrimaryDexCancelled("verify",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH, nullptr, nullptr);
+ service_->controlDexOptBlocking(false);
+}
+
+TEST_F(DexoptTest, DexoptUnblockPrimary) {
+ LOG(INFO) << "DexoptPrimaryPublic";
+ service_->controlDexOptBlocking(true);
+ service_->controlDexOptBlocking(false);
+ CompilePrimaryDexOk("verify",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH, nullptr, nullptr);
+}
+
TEST_F(DexoptTest, DeleteDexoptArtifactsData) {
LOG(INFO) << "DeleteDexoptArtifactsData";
TestDeleteOdex(/*in_dalvik_cache=*/ false);
@@ -1005,7 +1074,7 @@
_exit(0);
}
/* parent */
- ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+ ASSERT_TRUE(WIFEXITED(wait_child_with_timeout(pid, kTimeoutMs)));
}
void mergePackageProfiles(const std::string& package_name,
@@ -1191,6 +1260,7 @@
kTestUserId,
kAppDataFlags,
kTestAppUid,
+ 0 /* previousAppId */,
se_info_,
kOSdkVersion,
&ce_data_inode_));
@@ -1254,6 +1324,7 @@
kTestUserId,
kAppDataFlags,
kTestAppUid,
+ 0 /* previousAppId */,
se_info_,
kOSdkVersion,
&ce_data_inode));
@@ -1307,7 +1378,7 @@
_exit(0);
}
/* parent */
- ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+ ASSERT_TRUE(WIFEXITED(wait_child_with_timeout(pid, kTimeoutMs)));
}
protected:
std::string intial_android_profiles_dir;
diff --git a/cmds/installd/tests/installd_file_test.cpp b/cmds/installd/tests/installd_file_test.cpp
new file mode 100644
index 0000000..00fb308
--- /dev/null
+++ b/cmds/installd/tests/installd_file_test.cpp
@@ -0,0 +1,521 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "restorable_file.h"
+#include "unique_file.h"
+#include "utils.h"
+
+#undef LOG_TAG
+#define LOG_TAG "installd_file_test"
+
+namespace {
+
+constexpr char kFileTestDir[] = "/data/local/tmp/installd_file_test_data";
+constexpr char kTmpFileSuffix[] = ".tmp";
+constexpr char kBackupFileSuffix[] = ".backup";
+
+void UnlinkWithAssert(const std::string& path) {
+ ASSERT_EQ(0, unlink(path.c_str()));
+}
+
+} // namespace
+
+namespace android {
+namespace installd {
+
+// Add these as macros as functions make it hard to tell where the failure has happened.
+#define ASSERT_FILE_NOT_EXISTING(path) \
+ { \
+ struct stat st; \
+ ASSERT_NE(0, ::stat(path.c_str(), &st)); \
+ }
+#define ASSERT_FILE_EXISTING(path) \
+ { \
+ struct stat st; \
+ ASSERT_EQ(0, ::stat(path.c_str(), &st)); \
+ }
+#define ASSERT_FILE_CONTENT(path, expectedContent) ASSERT_EQ(expectedContent, ReadTestFile(path))
+#define ASSERT_FILE_OPEN(path, fd) \
+ { \
+ fd = open(path.c_str(), O_RDWR); \
+ ASSERT_TRUE(fd >= 0); \
+ }
+#define ASSERT_WRITE_TO_FD(fd, content) \
+ ASSERT_TRUE(android::base::WriteStringToFd(content, android::base::borrowed_fd(fd)))
+
+class FileTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+
+ ASSERT_EQ(0, create_dir_if_needed(kFileTestDir, 0777));
+ }
+
+ virtual void TearDown() {
+ system(android::base::StringPrintf("rm -rf %s", kFileTestDir).c_str());
+ }
+
+ std::string GetTestFilePath(const std::string& fileName) {
+ return android::base::StringPrintf("%s/%s", kFileTestDir, fileName.c_str());
+ }
+
+ void CreateTestFileWithContents(const std::string& path, const std::string& content) {
+ ALOGI("CreateTestFileWithContents:%s", path.c_str());
+ ASSERT_TRUE(android::base::WriteStringToFile(content, path));
+ }
+
+ std::string GetTestName() {
+ std::string name(testing::UnitTest::GetInstance()->current_test_info()->name());
+ return name;
+ }
+
+ std::string ReadTestFile(const std::string& path) {
+ std::string content;
+ bool r = android::base::ReadFileToString(path, &content);
+ if (!r) {
+ PLOG(ERROR) << "Cannot read file:" << path;
+ }
+ return content;
+ }
+};
+
+TEST_F(FileTest, TestUniqueFileMoveConstruction) {
+ const int fd = 101;
+ std::string testFile = GetTestFilePath(GetTestName());
+ UniqueFile uf1(fd, testFile);
+ uf1.DisableAutoClose();
+
+ UniqueFile uf2(std::move(uf1));
+
+ ASSERT_EQ(fd, uf2.fd());
+ ASSERT_EQ(testFile, uf2.path());
+}
+
+TEST_F(FileTest, TestUniqueFileAssignment) {
+ const int fd1 = 101;
+ const int fd2 = 102;
+ std::string testFile1 = GetTestFilePath(GetTestName());
+ std::string testFile2 = GetTestFilePath(GetTestName() + "2");
+
+ UniqueFile uf1(fd1, testFile1);
+ uf1.DisableAutoClose();
+
+ UniqueFile uf2(fd2, testFile2);
+ uf2.DisableAutoClose();
+
+ ASSERT_EQ(fd2, uf2.fd());
+ ASSERT_EQ(testFile2, uf2.path());
+
+ uf2 = std::move(uf1);
+
+ ASSERT_EQ(fd1, uf2.fd());
+ ASSERT_EQ(testFile1, uf2.path());
+}
+
+TEST_F(FileTest, TestUniqueFileCleanup) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ int fd;
+ ASSERT_FILE_OPEN(testFile, fd);
+
+ { UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert); }
+
+ ASSERT_FILE_NOT_EXISTING(testFile);
+}
+
+TEST_F(FileTest, TestUniqueFileNoCleanup) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ int fd;
+ ASSERT_FILE_OPEN(testFile, fd);
+
+ {
+ UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert);
+ uf.DisableCleanup();
+ }
+
+ ASSERT_FILE_CONTENT(testFile, "OriginalContent");
+}
+
+TEST_F(FileTest, TestUniqueFileFd) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ int fd;
+ ASSERT_FILE_OPEN(testFile, fd);
+
+ UniqueFile uf(fd, testFile, UnlinkWithAssert);
+
+ ASSERT_EQ(fd, uf.fd());
+
+ uf.reset();
+
+ ASSERT_EQ(-1, uf.fd());
+}
+
+TEST_F(FileTest, TestRestorableFileMoveConstruction) {
+ std::string testFile = GetTestFilePath(GetTestName());
+
+ RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile, 0600);
+ int fd = rf1.fd();
+
+ RestorableFile rf2(std::move(rf1));
+
+ ASSERT_EQ(fd, rf2.fd());
+ ASSERT_EQ(testFile, rf2.path());
+}
+
+TEST_F(FileTest, TestRestorableFileAssignment) {
+ std::string testFile1 = GetTestFilePath(GetTestName());
+ std::string testFile2 = GetTestFilePath(GetTestName() + "2");
+
+ RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile1, 0600);
+ int fd1 = rf1.fd();
+
+ RestorableFile rf2 = RestorableFile::CreateWritableFile(testFile2, 0600);
+ int fd2 = rf2.fd();
+
+ ASSERT_EQ(fd2, rf2.fd());
+ ASSERT_EQ(testFile2, rf2.path());
+
+ rf2 = std::move(rf1);
+
+ ASSERT_EQ(fd1, rf2.fd());
+ ASSERT_EQ(testFile1, rf2.path());
+}
+
+TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithReset) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+ ASSERT_FILE_EXISTING(tmpFile);
+
+ const UniqueFile& uf = rf.GetUniqueFile();
+
+ ASSERT_EQ(rf.fd(), uf.fd());
+ ASSERT_EQ(rf.path(), uf.path());
+
+ rf.reset();
+
+ ASSERT_EQ(rf.fd(), uf.fd());
+ ASSERT_EQ(rf.path(), uf.path());
+ ASSERT_EQ(-1, rf.fd());
+ ASSERT_TRUE(rf.path().empty());
+ }
+}
+
+TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithCommit) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+ ASSERT_FILE_EXISTING(tmpFile);
+
+ const UniqueFile& uf = rf.GetUniqueFile();
+
+ ASSERT_EQ(rf.fd(), uf.fd());
+ ASSERT_EQ(rf.path(), uf.path());
+
+ ASSERT_TRUE(rf.CreateBackupFile());
+
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+
+ rf.CommitWorkFile();
+
+ ASSERT_EQ(rf.fd(), uf.fd());
+ ASSERT_EQ(rf.path(), uf.path());
+ ASSERT_EQ(-1, rf.fd());
+ ASSERT_EQ(testFile, rf.path());
+ }
+}
+
+TEST_F(FileTest, TestRestorableFileNewFileNotCommitted) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+ ASSERT_FILE_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+ ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+}
+
+TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginal) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+ ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+ ASSERT_FILE_EXISTING(testFile);
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_CONTENT(testFile, "OriginalContent");
+}
+
+TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginalAndOldTmp) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+ CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+ ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+ ASSERT_FILE_EXISTING(testFile);
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_CONTENT(testFile, "OriginalContent");
+}
+
+TEST_F(FileTest, TestRestorableFileNewFileCommitted) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+
+ ASSERT_FILE_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+ ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+
+ ASSERT_TRUE(rf.CreateBackupFile());
+
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+
+ ASSERT_TRUE(rf.CommitWorkFile());
+ rf.RemoveBackupFile();
+
+ ASSERT_FILE_CONTENT(testFile, "NewContent");
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+ ASSERT_FILE_CONTENT(testFile, "NewContent");
+}
+
+TEST_F(FileTest, TestRestorableFileCommittedWithOriginal) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+ ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+
+ ASSERT_TRUE(rf.CreateBackupFile());
+
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_EXISTING(backupFile);
+
+ ASSERT_TRUE(rf.CommitWorkFile());
+
+ ASSERT_FILE_EXISTING(backupFile);
+ ASSERT_FILE_CONTENT(testFile, "NewContent");
+
+ rf.RemoveBackupFile();
+
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_CONTENT(testFile, "NewContent");
+}
+
+TEST_F(FileTest, TestRestorableFileCommittedWithOriginalAndOldTmp) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+ CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+ ASSERT_FILE_CONTENT(tmpFile, "NewContent");
+
+ ASSERT_TRUE(rf.CommitWorkFile());
+
+ ASSERT_FILE_CONTENT(testFile, "NewContent");
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_CONTENT(testFile, "NewContent");
+}
+
+TEST_F(FileTest, TestRestorableFileCommitFailureNoOriginal) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+ ASSERT_TRUE(rf.CreateBackupFile());
+
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+
+ // Now remove tmp file to force commit failure.
+ close(rf.fd());
+ ASSERT_EQ(0, unlink(tmpFile.c_str()));
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+
+ ASSERT_FALSE(rf.CommitWorkFile());
+
+ ASSERT_EQ(-1, rf.fd());
+ ASSERT_EQ(testFile, rf.path());
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+
+ ASSERT_TRUE(rf.RestoreBackupFile());
+ }
+
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileCommitFailureAndRollback) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+ ASSERT_TRUE(rf.CreateBackupFile());
+
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_EXISTING(backupFile);
+
+ // Now remove tmp file to force commit failure.
+ close(rf.fd());
+ ASSERT_EQ(0, unlink(tmpFile.c_str()));
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+
+ ASSERT_FALSE(rf.CommitWorkFile());
+
+ ASSERT_EQ(-1, rf.fd());
+ ASSERT_EQ(testFile, rf.path());
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_EXISTING(backupFile);
+
+ ASSERT_TRUE(rf.RestoreBackupFile());
+ }
+
+ ASSERT_FILE_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileResetAndRemoveAllFiles) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ {
+ RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
+ ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
+
+ ASSERT_TRUE(rf.CreateBackupFile());
+
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_EXISTING(backupFile);
+
+ rf.ResetAndRemoveAllFiles();
+
+ ASSERT_EQ(-1, rf.fd());
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+ }
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentFile) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+
+ RestorableFile::RemoveAllFiles(testFile);
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentAndTmpFile) {
+ std::string testFile = GetTestFilePath(GetTestName());
+ std::string tmpFile = testFile + kTmpFileSuffix;
+ std::string backupFile = testFile + kBackupFileSuffix;
+ CreateTestFileWithContents(testFile, "OriginalContent");
+ CreateTestFileWithContents(testFile + kTmpFileSuffix, "TmpContent");
+
+ RestorableFile::RemoveAllFiles(testFile);
+
+ ASSERT_FILE_NOT_EXISTING(tmpFile);
+ ASSERT_FILE_NOT_EXISTING(testFile);
+ ASSERT_FILE_NOT_EXISTING(backupFile);
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/tests/installd_file_test.xml b/cmds/installd/tests/installd_file_test.xml
new file mode 100644
index 0000000..5ec6e3f
--- /dev/null
+++ b/cmds/installd/tests/installd_file_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+ root support. -->
+<configuration description="Runs installd_file_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push"
+ value="installd_file_test->/data/local/tmp/installd_file_test" />
+ </target_preparer>
+
+ <!-- The test requires root for file access (rollback. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="installd_file_test" />
+ </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index b910ac1..effb401 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -32,16 +32,20 @@
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
+#include <filesystem>
+#include <fstream>
#include <android/content/pm/IPackageManagerNative.h>
#include <binder/IServiceManager.h>
#include "InstalldNativeService.h"
+#include "binder/Status.h"
#include "binder_test_utils.h"
#include "dexopt.h"
#include "globals.h"
#include "utils.h"
using android::base::StringPrintf;
+using std::filesystem::is_empty;
namespace android {
std::string get_package_name(uid_t uid) {
@@ -74,7 +78,20 @@
}
namespace installd {
-constexpr const char* kTestUuid = "TEST";
+static constexpr const char* kTestUuid = "TEST";
+static const std::string kTestPath = "/data/local/tmp";
+static constexpr const uid_t kNobodyUid = 9999;
+static constexpr const uid_t kSystemUid = 1000;
+static constexpr const int32_t kTestUserId = 0;
+static constexpr const uid_t kTestAppId = 19999;
+static constexpr const int FLAG_STORAGE_SDK = InstalldNativeService::FLAG_STORAGE_SDK;
+static constexpr const int FLAG_CLEAR_CACHE_ONLY = InstalldNativeService::FLAG_CLEAR_CACHE_ONLY;
+static constexpr const int FLAG_CLEAR_CODE_CACHE_ONLY =
+ InstalldNativeService::FLAG_CLEAR_CODE_CACHE_ONLY;
+
+const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+const gid_t kTestCacheGid = multiuser_get_cache_gid(kTestUserId, kTestAppId);
+const uid_t kTestSdkSandboxUid = multiuser_get_sdk_sandbox_uid(kTestUserId, kTestAppId);
#define FLAG_FORCE InstalldNativeService::FLAG_FORCE
@@ -96,23 +113,27 @@
return create_cache_path_default(path, src, instruction_set);
}
-static std::string get_full_path(const char* path) {
- return StringPrintf("/data/local/tmp/user/0/%s", path);
+static std::string get_full_path(const std::string& path) {
+ return StringPrintf("%s/%s", kTestPath.c_str(), path.c_str());
}
-static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static void mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
const std::string fullPath = get_full_path(path);
EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
}
-static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
+static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
EXPECT_NE(fd, -1);
EXPECT_EQ(::fchown(fd, owner, group), 0);
EXPECT_EQ(::fchmod(fd, mode), 0);
- EXPECT_EQ(::close(fd), 0);
+ return fd;
+}
+
+static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
+ EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0);
}
static int stat_gid(const char* path) {
@@ -127,6 +148,35 @@
return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
}
+static bool exists(const std::string& path) {
+ return ::access(get_full_path(path).c_str(), F_OK) == 0;
+}
+
+template <class Pred>
+static bool find_file(const char* path, Pred&& pred) {
+ bool result = false;
+ auto d = opendir(path);
+ if (d == nullptr) {
+ return result;
+ }
+ struct dirent* de;
+ while ((de = readdir(d))) {
+ const char* name = de->d_name;
+ if (pred(name, de->d_type == DT_DIR)) {
+ result = true;
+ break;
+ }
+ }
+ closedir(d);
+ return result;
+}
+
+static bool exists_renamed_deleted_dir(const std::string& rootDirectory) {
+ return find_file((kTestPath + rootDirectory).c_str(), [](const std::string& name, bool is_dir) {
+ return is_dir && is_renamed_deleted_dir(name);
+ });
+}
+
class ServiceTest : public testing::Test {
protected:
InstalldNativeService* service;
@@ -138,69 +188,206 @@
service = new InstalldNativeService();
testUuid = kTestUuid;
+ system("rm -rf /data/local/tmp/user");
+ system("rm -rf /data/local/tmp/misc_ce");
+ system("rm -rf /data/local/tmp/misc_de");
system("mkdir -p /data/local/tmp/user/0");
-
+ system("mkdir -p /data/local/tmp/misc_ce/0/sdksandbox");
+ system("mkdir -p /data/local/tmp/misc_de/0/sdksandbox");
init_globals_from_data_and_root();
}
virtual void TearDown() {
delete service;
system("rm -rf /data/local/tmp/user");
+ system("rm -rf /data/local/tmp/misc_ce");
+ system("rm -rf /data/local/tmp/misc_de");
}
};
TEST_F(ServiceTest, FixupAppData_Upgrade) {
LOG(INFO) << "FixupAppData_Upgrade";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/normal", 10000, 10000, 0700);
- mkdir("com.example/cache", 10000, 10000, 0700);
- touch("com.example/cache/file", 10000, 10000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/normal", 10000, 10000, 0700);
+ mkdir("user/0/com.example/cache", 10000, 10000, 0700);
+ touch("user/0/com.example/cache/file", 10000, 10000, 0700);
service->fixupAppData(testUuid, 0);
- EXPECT_EQ(10000, stat_gid("com.example/normal"));
- EXPECT_EQ(20000, stat_gid("com.example/cache"));
- EXPECT_EQ(20000, stat_gid("com.example/cache/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/normal"));
+ EXPECT_EQ(20000, stat_gid("user/0/com.example/cache"));
+ EXPECT_EQ(20000, stat_gid("user/0/com.example/cache/file"));
- EXPECT_EQ(0700, stat_mode("com.example/normal"));
- EXPECT_EQ(02771, stat_mode("com.example/cache"));
- EXPECT_EQ(0700, stat_mode("com.example/cache/file"));
+ EXPECT_EQ(0700, stat_mode("user/0/com.example/normal"));
+ EXPECT_EQ(02771, stat_mode("user/0/com.example/cache"));
+ EXPECT_EQ(0700, stat_mode("user/0/com.example/cache/file"));
}
TEST_F(ServiceTest, FixupAppData_Moved) {
LOG(INFO) << "FixupAppData_Moved";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
- mkdir("com.example/bar", 10000, 20000, 0700);
- touch("com.example/bar/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+ touch("user/0/com.example/bar/file", 10000, 20000, 0700);
service->fixupAppData(testUuid, 0);
- EXPECT_EQ(10000, stat_gid("com.example/foo"));
- EXPECT_EQ(20000, stat_gid("com.example/foo/file"));
- EXPECT_EQ(10000, stat_gid("com.example/bar"));
- EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+ EXPECT_EQ(20000, stat_gid("user/0/com.example/foo/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
service->fixupAppData(testUuid, FLAG_FORCE);
- EXPECT_EQ(10000, stat_gid("com.example/foo"));
- EXPECT_EQ(10000, stat_gid("com.example/foo/file"));
- EXPECT_EQ(10000, stat_gid("com.example/bar"));
- EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/foo"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/foo/file"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar"));
+ EXPECT_EQ(10000, stat_gid("user/0/com.example/bar/file"));
+}
+
+TEST_F(ServiceTest, DestroyUserData) {
+ LOG(INFO) << "DestroyUserData";
+
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+ touch("user/0/com.example/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("user/0/com.example/foo"));
+ EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+ EXPECT_TRUE(exists("user/0/com.example/bar"));
+ EXPECT_TRUE(exists("user/0/com.example/bar/file"));
+
+ service->destroyUserData(testUuid, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE);
+
+ EXPECT_FALSE(exists("user/0/com.example/foo"));
+ EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+ EXPECT_FALSE(exists("user/0/com.example/bar"));
+ EXPECT_FALSE(exists("user/0/com.example/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
+}
+
+TEST_F(ServiceTest, DestroyAppData) {
+ LOG(INFO) << "DestroyAppData";
+
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example/bar", 10000, 20000, 0700);
+ touch("user/0/com.example/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists("user/0/com.example/foo"));
+ EXPECT_TRUE(exists("user/0/com.example/foo/file"));
+ EXPECT_TRUE(exists("user/0/com.example/bar"));
+ EXPECT_TRUE(exists("user/0/com.example/bar/file"));
+
+ service->destroyAppData(testUuid, "com.example", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, 0);
+
+ EXPECT_FALSE(exists("user/0/com.example/foo"));
+ EXPECT_FALSE(exists("user/0/com.example/foo/file"));
+ EXPECT_FALSE(exists("user/0/com.example/bar"));
+ EXPECT_FALSE(exists("user/0/com.example/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir("/user/0"));
+}
+
+TEST_F(ServiceTest, CleanupInvalidPackageDirs) {
+ LOG(INFO) << "CleanupInvalidPackageDirs";
+
+ std::string rootDirectoryPrefix[] = {"user/0", "misc_ce/0/sdksandbox", "misc_de/0/sdksandbox"};
+ for (auto& prefix : rootDirectoryPrefix) {
+ mkdir(prefix + "/5b14b6458a44==deleted==", 10000, 10000, 0700);
+ mkdir(prefix + "/5b14b6458a44==deleted==/foo", 10000, 10000, 0700);
+ touch(prefix + "/5b14b6458a44==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/5b14b6458a44==deleted==/bar", 10000, 20000, 0700);
+ touch(prefix + "/5b14b6458a44==deleted==/bar/file", 10000, 20000, 0700);
+
+ auto fd = create(prefix + "/5b14b6458a44==deleted==/bar/opened_file", 10000, 20000, 0700);
+
+ mkdir(prefix + "/b14b6458a44NOTdeleted", 10000, 10000, 0700);
+ mkdir(prefix + "/b14b6458a44NOTdeleted/foo", 10000, 10000, 0700);
+ touch(prefix + "/b14b6458a44NOTdeleted/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/b14b6458a44NOTdeleted/bar", 10000, 20000, 0700);
+ touch(prefix + "/b14b6458a44NOTdeleted/bar/file", 10000, 20000, 0700);
+
+ mkdir(prefix + "/com.example", 10000, 10000, 0700);
+ mkdir(prefix + "/com.example/foo", 10000, 10000, 0700);
+ touch(prefix + "/com.example/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/com.example/bar", 10000, 20000, 0700);
+ touch(prefix + "/com.example/bar/file", 10000, 20000, 0700);
+
+ mkdir(prefix + "/==deleted==", 10000, 10000, 0700);
+ mkdir(prefix + "/==deleted==/foo", 10000, 10000, 0700);
+ touch(prefix + "/==deleted==/foo/file", 10000, 20000, 0700);
+ mkdir(prefix + "/==deleted==/bar", 10000, 20000, 0700);
+ touch(prefix + "/==deleted==/bar/file", 10000, 20000, 0700);
+
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+ EXPECT_TRUE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+ EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
+
+ EXPECT_TRUE(exists(prefix + "/==deleted==/foo"));
+ EXPECT_TRUE(exists(prefix + "/==deleted==/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/==deleted==/bar"));
+ EXPECT_TRUE(exists(prefix + "/==deleted==/bar/file"));
+
+ EXPECT_TRUE(exists_renamed_deleted_dir("/" + prefix));
+
+ service->cleanupInvalidPackageDirs(testUuid, 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE);
+
+ EXPECT_EQ(::close(fd), 0);
+
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/foo/file"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/file"));
+ EXPECT_FALSE(exists(prefix + "/5b14b6458a44==deleted==/bar/opened_file"));
+
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar"));
+ EXPECT_TRUE(exists(prefix + "/b14b6458a44NOTdeleted/bar/file"));
+
+ EXPECT_TRUE(exists(prefix + "/com.example/foo"));
+ EXPECT_TRUE(exists(prefix + "/com.example/foo/file"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar"));
+ EXPECT_TRUE(exists(prefix + "/com.example/bar/file"));
+
+ EXPECT_FALSE(exists(prefix + "/==deleted==/foo"));
+ EXPECT_FALSE(exists(prefix + "/==deleted==/foo/file"));
+ EXPECT_FALSE(exists(prefix + "/==deleted==/bar"));
+ EXPECT_FALSE(exists(prefix + "/==deleted==/bar/file"));
+
+ EXPECT_FALSE(exists_renamed_deleted_dir(prefix));
+ }
}
TEST_F(ServiceTest, HashSecondaryDex) {
LOG(INFO) << "HashSecondaryDex";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
@@ -220,7 +407,7 @@
LOG(INFO) << "HashSecondaryDex_NoSuch";
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
@@ -230,12 +417,12 @@
TEST_F(ServiceTest, HashSecondaryDex_Unreadable) {
LOG(INFO) << "HashSecondaryDex_Unreadable";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0300);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0300);
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
@@ -245,12 +432,12 @@
TEST_F(ServiceTest, HashSecondaryDex_WrongApp) {
LOG(INFO) << "HashSecondaryDex_WrongApp";
- mkdir("com.example", 10000, 10000, 0700);
- mkdir("com.example/foo", 10000, 10000, 0700);
- touch("com.example/foo/file", 10000, 20000, 0700);
+ mkdir("user/0/com.example", 10000, 10000, 0700);
+ mkdir("user/0/com.example/foo", 10000, 10000, 0700);
+ touch("user/0/com.example/foo/file", 10000, 20000, 0700);
std::vector<uint8_t> result;
- std::string dexPath = get_full_path("com.example/foo/file");
+ std::string dexPath = get_full_path("user/0/com.example/foo/file");
EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
}
@@ -278,7 +465,7 @@
EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
-TEST_F(ServiceTest, GetAppSize) {
+TEST_F(ServiceTest, GetAppSizeManualForMedia) {
struct stat s;
std::string externalPicDir =
@@ -322,6 +509,100 @@
system(removeCommand.c_str());
}
}
+// TEST_F(ServiceTest, GetAppSizeProjectID_UID) {
+// struct stat s;
+// std::string externalPicDir =
+// StringPrintf("%s/Pictures", create_data_media_path(nullptr, 0).c_str());
+// if (stat(externalPicDir.c_str(), &s) == 0) {
+// // fetch the appId from the uid of the external storage owning app
+// int32_t externalStorageAppId = multiuser_get_app_id(s.st_uid);
+// // Fetch Package Name for the external storage owning app uid
+// std::string pkg = get_package_name(s.st_uid);
+//
+// std::vector<int64_t> externalStorageSize, externalStorageSizeAfterAddingCacheFile;
+// std::vector<int64_t> ceDataInodes;
+//
+// std::vector<std::string> codePaths;
+// std::vector<std::string> packageNames;
+// // set up parameters
+// packageNames.push_back(pkg);
+// ceDataInodes.push_back(0);
+// // initialise the mounts
+// service->invalidateMounts();
+// auto using_project_ids =
+// StringPrintf("%smisc/installd/using_project_ids", android_data_dir.c_str());
+// bool usingProjectIds = access(using_project_ids.c_str(), F_OK) == 0;
+// if (!usingProjectIds) {
+// service->setFirstBoot();
+// }
+//
+// if (access(using_project_ids.c_str(), F_OK) != 0) {
+// // projectids is not used, so check that ioctl features should be absent
+// auto temp_path = StringPrintf("%smisc/installd/ioctl_check",
+// android_data_dir.c_str());
+//
+// if (access(temp_path.c_str(), F_OK) != 0) {
+// open(temp_path.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
+// bool result = set_quota_project_id(temp_path, 0, false) == 0;
+// // delete the temp file
+// // remove the external file
+// remove(temp_path.c_str());
+// // since using_project_ids file is not present, so ioctl settings should be
+// absent
+// // that is denoted by the result of setting project id flag as false
+// ASSERT_FALSE(result);
+// }
+// }
+// // call the getAppSize to get the current size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize);
+// // add a file with 20MB size to the external storage
+// std::string externalStorageCacheDir =
+// StringPrintf("%s/%s/cache", create_data_user_ce_path(nullptr, 0).c_str(),
+// pkg.c_str());
+// std::string cacheFileLocation =
+// StringPrintf("%s/%s", externalStorageCacheDir.c_str(), "External.jpg");
+// std::string externalFileContentCommand =
+// StringPrintf("dd if=/dev/zero of=%s bs=1M count=20", cacheFileLocation.c_str());
+// system(externalFileContentCommand.c_str());
+// // call the getAppSize again to get the new size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths,
+// &externalStorageSizeAfterAddingCacheFile);
+// // check that the size of cache and data increases when cache file is added
+// int64_t sizeDiffData = externalStorageSizeAfterAddingCacheFile[1] -
+// externalStorageSize[1]; int64_t sizeDiffCache =
+// externalStorageSizeAfterAddingCacheFile[2] - externalStorageSize[2];
+// ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+// // remove the external file
+// std::string removeCommand = StringPrintf("rm -f %s", cacheFileLocation.c_str());
+// system(removeCommand.c_str());
+// // remove the setFirstBoot setting
+// std::string removeCommand2 = "rm -f /data/misc/installd/using_project_ids";
+// system(removeCommand2.c_str());
+// // Do now without project id
+// std::vector<int64_t> sizeWithUID, sizeWithUIDAfterAddingCacheFile;
+// // call the getAppSize to get the current size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths, &sizeWithUID);
+// // add a file with 20MB size to the external storage
+// system(externalFileContentCommand.c_str());
+// // call the getAppSize again to get the new size of the external storage owning app
+// service->getAppSize(std::nullopt, packageNames, 0, InstalldNativeService::FLAG_USE_QUOTA,
+// externalStorageAppId, ceDataInodes, codePaths,
+// &sizeWithUIDAfterAddingCacheFile);
+// // check that the size of cache and data increases when cache file is added
+// sizeDiffData = sizeWithUIDAfterAddingCacheFile[1] - sizeWithUID[1];
+// sizeDiffCache = sizeWithUIDAfterAddingCacheFile[2] - sizeWithUID[2];
+// ASSERT_TRUE(sizeDiffData == sizeDiffCache);
+// // remove the external file
+// system(removeCommand.c_str());
+// // reset the using_project_id if it was initially set
+// if (usingProjectIds) {
+// service->setFirstBoot();
+// }
+// }
+// }
TEST_F(ServiceTest, GetAppSizeWrongSizes) {
int32_t externalStorageAppId = -1;
std::vector<int64_t> externalStorageSize;
@@ -780,5 +1061,364 @@
"com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
}
+class SdkSandboxDataTest : public testing::Test {
+public:
+ void CheckFileAccess(const std::string& path, uid_t uid, gid_t gid, mode_t mode) {
+ const auto fullPath = "/data/local/tmp/" + path;
+ ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath;
+ struct stat st;
+ ASSERT_EQ(0, stat(fullPath.c_str(), &st));
+ ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath;
+ ASSERT_EQ(gid, st.st_gid) << "For path: " << fullPath;
+ ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath;
+ }
+
+ bool exists(const char* path) { return ::access(path, F_OK) == 0; }
+
+ // Creates a default CreateAppDataArgs object
+ android::os::CreateAppDataArgs createAppDataArgs(const std::string& packageName) {
+ android::os::CreateAppDataArgs args;
+ args.uuid = kTestUuid;
+ args.packageName = packageName;
+ args.userId = kTestUserId;
+ args.appId = kTestAppId;
+ args.seInfo = "default";
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
+ return args;
+ }
+
+ android::os::ReconcileSdkDataArgs reconcileSdkDataArgs(
+ const std::string& packageName, const std::vector<std::string>& subDirNames) {
+ android::os::ReconcileSdkDataArgs args;
+ args.uuid = kTestUuid;
+ args.packageName = packageName;
+ for (const auto& subDirName : subDirNames) {
+ args.subDirNames.push_back(subDirName);
+ }
+ args.userId = kTestUserId;
+ args.appId = kTestAppId;
+ args.previousAppId = -1;
+ args.seInfo = "default";
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ return args;
+ }
+
+protected:
+ InstalldNativeService* service;
+
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
+
+ service = new InstalldNativeService();
+ clearAppData();
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/sdksandbox", 0700));
+ ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/sdksandbox", 0700));
+
+ init_globals_from_data_and_root();
+ }
+
+ virtual void TearDown() {
+ delete service;
+ clearAppData();
+ }
+
+private:
+ void clearAppData() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true));
+ }
+};
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ const std::string fooCePath = "misc_ce/0/sdksandbox/com.foo";
+ CheckFileAccess(fooCePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+
+ const std::string fooDePath = "misc_de/0/sdksandbox/com.foo";
+ CheckFileAccess(fooDePath, kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutSdkFlagDeletesExisting) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_SDK;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ // Only CE paths should exist
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
+
+ // DE paths should not exist
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(SdkSandboxDataTest, CreateAppData_CreatesSdkPackageData_WithoutCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.flags = FLAG_STORAGE_DE | FLAG_STORAGE_SDK;
+
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+
+ // CE paths should not exist
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+
+ // Only DE paths should exist
+ CheckFileAccess("misc_de/0/sdksandbox/com.foo", kSystemUid, kSystemUid, S_IFDIR | 0751);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData) {
+ android::os::ReconcileSdkDataArgs args =
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+ // Create the sdk data.
+ ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+ const std::string barCePath = "misc_ce/0/sdksandbox/com.foo/bar@random1";
+ CheckFileAccess(barCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(barCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(barCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+
+ const std::string bazCePath = "misc_ce/0/sdksandbox/com.foo/baz@random2";
+ CheckFileAccess(bazCePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(bazCePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(bazCePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+
+ const std::string barDePath = "misc_de/0/sdksandbox/com.foo/bar@random1";
+ CheckFileAccess(barDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(barDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(barDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+
+ const std::string bazDePath = "misc_de/0/sdksandbox/com.foo/baz@random2";
+ CheckFileAccess(bazDePath, kTestSdkSandboxUid, kNobodyUid, S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess(bazDePath + "/cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+ CheckFileAccess(bazDePath + "/code_cache", kTestSdkSandboxUid, kTestCacheGid,
+ S_IFDIR | S_ISGID | 0771);
+}
+
+TEST_F(SdkSandboxDataTest, ReconcileSdkData_ExtraCodeDirectoriesAreDeleted) {
+ android::os::ReconcileSdkDataArgs args =
+ reconcileSdkDataArgs("com.foo", {"bar@random1", "baz@random2"});
+
+ // Create the sdksandbox data.
+ ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+ // Retry with different package name
+ args.subDirNames[0] = "bar.diff@random1";
+
+ // Create the sdksandbox data again
+ ASSERT_BINDER_SUCCESS(service->reconcileSdkData(args));
+
+ // New directoris should exist
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo/bar.diff@random1", kTestSdkSandboxUid, kNobodyUid,
+ S_IFDIR | S_ISGID | 0700);
+ CheckFileAccess("misc_ce/0/sdksandbox/com.foo/baz@random2", kTestSdkSandboxUid, kNobodyUid,
+ S_IFDIR | S_ISGID | 0700);
+ // Directory for old unreferred sdksandbox package name should be removed
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo/bar@random1"));
+}
+
+class DestroyAppDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithCeAndDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy the app user data.
+ ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+ args.flags, result.ceDataInode));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy the app user data.
+ ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+ FLAG_STORAGE_CE, result.ceDataInode));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+}
+
+TEST_F(DestroyAppDataTest, DestroySdkSandboxDataDirectories_WithoutCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy the app user data.
+ ASSERT_BINDER_SUCCESS(service->destroyAppData(args.uuid, args.packageName, args.userId,
+ FLAG_STORAGE_DE, result.ceDataInode));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox/com.foo"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox/com.foo"));
+}
+
+class ClearAppDataTest : public SdkSandboxDataTest {
+public:
+ void createTestSdkData(const std::string& packageName, std::vector<std::string> sdkNames) {
+ const auto& cePackagePath = "/data/local/tmp/misc_ce/0/sdksandbox/" + packageName;
+ const auto& dePackagePath = "/data/local/tmp/misc_de/0/sdksandbox/" + packageName;
+ ASSERT_TRUE(mkdirs(cePackagePath, 0700));
+ ASSERT_TRUE(mkdirs(dePackagePath, 0700));
+ const std::vector<std::string> packagePaths = {cePackagePath, dePackagePath};
+ for (const auto& packagePath : packagePaths) {
+ for (auto sdkName : sdkNames) {
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/cache", 0700));
+ ASSERT_TRUE(mkdirs(packagePath + "/" + sdkName + "/code_cache", 0700));
+ std::ofstream{packagePath + "/" + sdkName + "/cache/cachedTestData.txt"};
+ std::ofstream{packagePath + "/" + sdkName + "/code_cache/cachedTestData.txt"};
+ }
+ }
+ }
+};
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndClearCodeCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_CE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data
+ ASSERT_BINDER_SUCCESS(
+ service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_DE | (InstalldNativeService::FLAG_CLEAR_CACHE_ONLY),
+ -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndClearCodeCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0,
+ FLAG_STORAGE_DE | FLAG_CLEAR_CODE_CACHE_ONLY, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1/code_cache"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2/code_cache"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithCeAndWithoutAnyCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_CE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_ce/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+TEST_F(ClearAppDataTest, ClearSdkSandboxDataDirectories_WithDeAndWithoutAnyCacheFlag) {
+ createTestSdkData("com.foo", {"shared", "sdk1", "sdk2"});
+ // Clear the app user data.
+ ASSERT_BINDER_SUCCESS(service->clearAppData(kTestUuid, "com.foo", 0, FLAG_STORAGE_DE, -1));
+
+ const std::string packagePath = kTestPath + "/misc_de/0/sdksandbox/com.foo";
+ ASSERT_TRUE(is_empty(packagePath + "/shared"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk1"));
+ ASSERT_TRUE(is_empty(packagePath + "/sdk2"));
+}
+
+class DestroyUserDataTest : public SdkSandboxDataTest {};
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithCeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_CE));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
+TEST_F(DestroyUserDataTest, DestroySdkData_WithDeFlag) {
+ android::os::CreateAppDataResult result;
+ android::os::CreateAppDataArgs args = createAppDataArgs("com.foo");
+ args.packageName = "com.foo";
+ // Create the app user data.
+ ASSERT_BINDER_SUCCESS(service->createAppData(args, &result));
+ // Destroy user data
+ ASSERT_BINDER_SUCCESS(service->destroyUserData(args.uuid, args.userId, FLAG_STORAGE_DE));
+ ASSERT_TRUE(exists("/data/local/tmp/misc_ce/0/sdksandbox"));
+ ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/sdksandbox"));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ed87b67..910cd63 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
@@ -45,6 +48,8 @@
namespace android {
namespace installd {
+using ::testing::UnorderedElementsAre;
+
class UtilsTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -555,6 +560,24 @@
EXPECT_EQ(0, MatchExtension("docx"));
}
+TEST_F(UtilsTest, TestIsRenamedDeletedDir) {
+ EXPECT_FALSE(is_renamed_deleted_dir(""));
+ EXPECT_FALSE(is_renamed_deleted_dir("1"));
+ EXPECT_FALSE(is_renamed_deleted_dir("="));
+ EXPECT_FALSE(is_renamed_deleted_dir("=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("d=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("ed=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("ted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("eted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("leted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("eleted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("deleted=="));
+ EXPECT_FALSE(is_renamed_deleted_dir("=deleted=="));
+ EXPECT_TRUE(is_renamed_deleted_dir("==deleted=="));
+ EXPECT_TRUE(is_renamed_deleted_dir("123==deleted=="));
+ EXPECT_TRUE(is_renamed_deleted_dir("5b14b6458a44==deleted=="));
+}
+
TEST_F(UtilsTest, TestRollbackPaths) {
EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
@@ -638,5 +661,98 @@
ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}
+TEST_F(UtilsTest, TestForEachSubdir) {
+ auto deleter = [&]() {
+ delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ system("mkdir -p /data/local/tmp/user/0/com.foo");
+ system("mkdir -p /data/local/tmp/user/0/com.bar");
+ system("touch /data/local/tmp/user/0/some-file");
+
+ std::vector<std::string> result;
+ foreach_subdir("/data/local/tmp/user/0",
+ [&](const std::string &filename) { result.push_back(filename); });
+
+ EXPECT_THAT(result, UnorderedElementsAre("com.foo", "com.bar"));
+}
+
+TEST_F(UtilsTest, TestSdkSandboxDataPaths) {
+ // Ce data paths
+ EXPECT_EQ("/data/misc_ce/0/sdksandbox",
+ create_data_misc_sdk_sandbox_path(nullptr, /*isCeData=*/true, 0));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox", create_data_misc_sdk_sandbox_path(nullptr, true, 10));
+
+ EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, true, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, true, 10, "com.foo"));
+
+ EXPECT_EQ("/data/misc_ce/0/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 0, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_ce/10/sdksandbox/com.foo/bar@random",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, true, 10, "com.foo", "bar@random"));
+
+ // De data paths
+ EXPECT_EQ("/data/misc_de/0/sdksandbox",
+ create_data_misc_sdk_sandbox_path(nullptr, /*isCeData=*/false, 0));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox", create_data_misc_sdk_sandbox_path(nullptr, false, 10));
+
+ EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, false, 0, "com.foo"));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo",
+ create_data_misc_sdk_sandbox_package_path(nullptr, false, 10, "com.foo"));
+
+ EXPECT_EQ("/data/misc_de/0/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 0, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/shared",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "shared"));
+ EXPECT_EQ("/data/misc_de/10/sdksandbox/com.foo/bar@random",
+ create_data_misc_sdk_sandbox_sdk_path(nullptr, false, 10, "com.foo", "bar@random"));
+}
+
+TEST_F(UtilsTest, WaitChild) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child */
+ // Do nothing.
+ _exit(0);
+ }
+ /* parent */
+ int return_code = wait_child_with_timeout(pid, /*timeout_ms=*/100);
+ EXPECT_TRUE(WIFEXITED(return_code));
+ EXPECT_EQ(WEXITSTATUS(return_code), 0);
+}
+
+TEST_F(UtilsTest, WaitChildTimeout) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child */
+ sleep(1);
+ _exit(0);
+ }
+ /* parent */
+ int return_code = wait_child_with_timeout(pid, /*timeout_ms=*/1);
+ EXPECT_FALSE(WIFEXITED(return_code));
+ EXPECT_EQ(WTERMSIG(return_code), SIGKILL);
+}
+
+TEST_F(UtilsTest, RemoveFileAtFd) {
+ std::string filename = "/data/local/tmp/tempfile-XXXXXX";
+ int fd = mkstemp(filename.data());
+ ASSERT_GE(fd, 0);
+ ASSERT_EQ(access(filename.c_str(), F_OK), 0);
+
+ std::string actual_filename;
+ remove_file_at_fd(fd, &actual_filename);
+ EXPECT_NE(access(filename.c_str(), F_OK), 0);
+ EXPECT_EQ(filename, actual_filename);
+
+ close(fd);
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c4ecd07..c7bea3f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -19,20 +19,25 @@
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
+#include <poll.h>
#include <stdlib.h>
#include <sys/capability.h>
+#include <sys/pidfd.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/wait.h>
#include <sys/xattr.h>
-#include <sys/statvfs.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
+#include <linux/fs.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <private/android_projectid_config.h>
@@ -47,6 +52,7 @@
#define DEBUG_XATTRS 0
+using android::base::Dirname;
using android::base::EndsWith;
using android::base::Fdopendir;
using android::base::StringPrintf;
@@ -55,6 +61,10 @@
namespace android {
namespace installd {
+using namespace std::literals;
+
+static constexpr auto deletedSuffix = "==deleted=="sv;
+
/**
* Check that given string is valid filename, and that it attempts no
* parent or child directory traversal.
@@ -188,6 +198,45 @@
return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}
+/**
+ * Create the path name where sdk_sandbox data for all apps will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox
+ */
+std::string create_data_misc_sdk_sandbox_path(const char* uuid, bool isCeData, userid_t user) {
+ std::string data(create_data_path(uuid));
+ if (isCeData) {
+ return StringPrintf("%s/misc_ce/%d/sdksandbox", data.c_str(), user);
+ } else {
+ return StringPrintf("%s/misc_de/%d/sdksandbox", data.c_str(), user);
+ }
+}
+
+/**
+ * Create the path name where code data for all codes in a particular app will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>
+ */
+std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
+ userid_t user, const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/%s",
+ create_data_misc_sdk_sandbox_path(volume_uuid, isCeData, user).c_str(),
+ package_name);
+}
+
+/**
+ * Create the path name where sdk data for a particular sdk will be stored.
+ * E.g. /data/misc_ce/0/sdksandbox/<package-name>/com.foo@randomstrings
+ */
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+ userid_t user, const char* package_name,
+ const char* sub_dir_name) {
+ return StringPrintf("%s/%s",
+ create_data_misc_sdk_sandbox_package_path(volume_uuid, isCeData, user,
+ package_name)
+ .c_str(),
+ sub_dir_name);
+}
+
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
@@ -375,7 +424,44 @@
return users;
}
+long get_project_id(uid_t uid, long start_project_id_range) {
+ return uid - AID_APP_START + start_project_id_range;
+}
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit) {
+ struct fsxattr fsx;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << path << " to set project id.";
+ return -1;
+ }
+
+ if (ioctl(fd, FS_IOC_FSGETXATTR, &fsx) == -1) {
+ PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id.";
+ return -1;
+ }
+
+ fsx.fsx_projid = project_id;
+ if (ioctl(fd, FS_IOC_FSSETXATTR, &fsx) == -1) {
+ PLOG(ERROR) << "Failed to set project id on " << path;
+ return -1;
+ }
+ if (set_inherit) {
+ unsigned int flags;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) {
+ PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance.";
+ return -1;
+ }
+
+ flags |= FS_PROJINHERIT_FL;
+
+ if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == -1) {
+ PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance.";
+ return -1;
+ }
+ }
+ return 0;
+}
int calculate_tree_size(const std::string& path, int64_t* size,
int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
FTS *fts;
@@ -595,6 +681,125 @@
return res;
}
+static std::string make_unique_name(std::string_view suffix) {
+ static constexpr auto uuidStringSize = 36;
+
+ uuid_t guid;
+ uuid_generate(guid);
+
+ std::string name;
+ const auto suffixSize = suffix.size();
+ name.reserve(uuidStringSize + suffixSize);
+
+ name.resize(uuidStringSize);
+ uuid_unparse(guid, name.data());
+ name.append(suffix);
+
+ return name;
+}
+
+static int rename_delete_dir_contents(const std::string& pathname,
+ int (*exclusion_predicate)(const char*, const int),
+ bool ignore_if_missing) {
+ auto temp_dir_name = make_unique_name(deletedSuffix);
+ auto temp_dir_path =
+ base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str());
+
+ auto dir_to_delete = temp_dir_path.c_str();
+ if (::rename(pathname.c_str(), dir_to_delete)) {
+ if (ignore_if_missing && (errno == ENOENT)) {
+ return 0;
+ }
+ ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), dir_to_delete, strerror(errno));
+ dir_to_delete = pathname.c_str();
+ }
+
+ return delete_dir_contents(dir_to_delete, 1, exclusion_predicate, ignore_if_missing);
+}
+
+bool is_renamed_deleted_dir(const std::string& path) {
+ if (path.size() < deletedSuffix.size()) {
+ return false;
+ }
+ std::string_view pathSuffix{path.c_str() + path.size() - deletedSuffix.size()};
+ return pathSuffix == deletedSuffix;
+}
+
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
+ return rename_delete_dir_contents(pathname, nullptr, ignore_if_missing);
+}
+
+static auto open_dir(const char* dir) {
+ struct DirCloser {
+ void operator()(DIR* d) const noexcept { ::closedir(d); }
+ };
+ return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
+}
+
+// Collects filename of subdirectories of given directory and passes it to the function
+int foreach_subdir(const std::string& pathname, const std::function<void(const std::string&)> fn) {
+ auto dir = open_dir(pathname.c_str());
+ if (!dir) return -1;
+
+ int dfd = dirfd(dir.get());
+ if (dfd < 0) {
+ ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+ return -1;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_DIR) {
+ continue;
+ }
+
+ std::string name{de->d_name};
+ // always skip "." and ".."
+ if (name == "." || name == "..") {
+ continue;
+ }
+ fn(name);
+ }
+
+ return 0;
+}
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname) {
+ auto dir = open_dir(pathname.c_str());
+ if (!dir) {
+ return;
+ }
+ int dfd = dirfd(dir.get());
+ if (dfd < 0) {
+ ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno));
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_DIR) {
+ continue;
+ }
+
+ std::string name{de->d_name};
+ // always skip "." and ".."
+ if (name == "." || name == "..") {
+ continue;
+ }
+
+ if (is_renamed_deleted_dir(name) || !is_valid_filename(name) ||
+ !is_valid_package_name(name)) {
+ ALOGI("Deleting renamed or invalid data directory: %s\n", name.c_str());
+ // Deleting the content.
+ delete_dir_contents_fd(dfd, name.c_str());
+ // Deleting the directory
+ if (unlinkat(dfd, name.c_str(), AT_REMOVEDIR) < 0) {
+ ALOGE("Couldn't unlinkat %s: %s\n", name.c_str(), strerror(errno));
+ }
+ }
+ }
+}
+
int delete_dir_contents_fd(int dfd, const char *name)
{
int fd, res;
@@ -829,7 +1034,7 @@
* to top level directories (i.e. have "..").
*/
static int validate_path(const std::string& dir, const std::string& path, int maxSubdirs) {
- // Argument sanity checking
+ // Argument check
if (dir.find('/') != 0 || dir.rfind('/') != dir.size() - 1
|| dir.find("..") != std::string::npos) {
LOG(ERROR) << "Invalid directory " << dir;
@@ -962,30 +1167,45 @@
return fs_prepare_dir(path.c_str(), 0750, uid, gid);
}
-int wait_child(pid_t pid)
-{
+static int wait_child(pid_t pid) {
int status;
- pid_t got_pid;
+ pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, /*options=*/0));
- while (1) {
- got_pid = waitpid(pid, &status, 0);
- if (got_pid == -1 && errno == EINTR) {
- printf("waitpid interrupted, retrying\n");
- } else {
- break;
- }
- }
if (got_pid != pid) {
- ALOGW("waitpid failed: wanted %d, got %d: %s\n",
- (int) pid, (int) got_pid, strerror(errno));
- return 1;
+ PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
+ return W_EXITCODE(/*exit_code=*/255, /*signal_number=*/0);
}
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- return 0;
- } else {
- return status; /* always nonzero */
+ return status;
+}
+
+int wait_child_with_timeout(pid_t pid, int timeout_ms) {
+ int pidfd = pidfd_open(pid, /*flags=*/0);
+ if (pidfd < 0) {
+ PLOG(ERROR) << "pidfd_open failed for pid " << pid;
+ kill(pid, SIGKILL);
+ return wait_child(pid);
}
+
+ struct pollfd pfd;
+ pfd.fd = pidfd;
+ pfd.events = POLLIN;
+ int poll_ret = TEMP_FAILURE_RETRY(poll(&pfd, /*nfds=*/1, timeout_ms));
+
+ close(pidfd);
+
+ if (poll_ret < 0) {
+ PLOG(ERROR) << "poll failed for pid " << pid;
+ kill(pid, SIGKILL);
+ return wait_child(pid);
+ }
+ if (poll_ret == 0) {
+ LOG(WARNING) << "Child process " << pid << " timed out after " << timeout_ms
+ << "ms. Killing it";
+ kill(pid, SIGKILL);
+ return wait_child(pid);
+ }
+ return wait_child(pid);
}
/**
@@ -1198,5 +1418,27 @@
}
}
+bool remove_file_at_fd(int fd, /*out*/ std::string* path) {
+ char path_buffer[PATH_MAX + 1];
+ std::string proc_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
+ ssize_t len = readlink(proc_path.c_str(), path_buffer, PATH_MAX);
+ if (len < 0) {
+ PLOG(WARNING) << "Could not remove file at fd " << fd << ": Failed to get file path";
+ return false;
+ }
+ path_buffer[len] = '\0';
+ if (path != nullptr) {
+ *path = path_buffer;
+ }
+ if (unlink(path_buffer) != 0) {
+ if (errno == ENOENT) {
+ return true;
+ }
+ PLOG(WARNING) << "Could not remove file at path " << path_buffer;
+ return false;
+ }
+ return true;
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 549fc6c..ecea1d2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -32,6 +32,7 @@
#define MEASURE_DEBUG 0
#define FIXUP_DEBUG 0
+#define SDK_DEBUG 1
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
@@ -60,6 +61,14 @@
std::string create_data_user_ce_package_path_as_user_link(
const char* volume_uuid, userid_t userid, const char* package_name);
+std::string create_data_misc_sdk_sandbox_path(const char* volume_uuid, bool isCeData,
+ userid_t userid);
+std::string create_data_misc_sdk_sandbox_package_path(const char* volume_uuid, bool isCeData,
+ userid_t userid, const char* package_name);
+std::string create_data_misc_sdk_sandbox_sdk_path(const char* volume_uuid, bool isCeData,
+ userid_t userid, const char* package_name,
+ const char* sub_dir_name);
+
std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
@@ -120,6 +129,13 @@
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
+bool is_renamed_deleted_dir(const std::string& path);
+int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = true);
+
+int foreach_subdir(const std::string& pathname, std::function<void(const std::string&)> fn);
+
+void cleanup_invalid_package_dirs_under_path(const std::string& pathname);
+
int delete_dir_contents(const char *pathname,
int also_delete_dir,
int (*exclusion_predicate)(const char *name, const int is_dir),
@@ -148,12 +164,15 @@
int ensure_config_user_dirs(userid_t userid);
-int wait_child(pid_t pid);
+// Waits for a child process, or kills it if it times out. Returns the exit code.
+int wait_child_with_timeout(pid_t pid, int timeout_ms);
int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
uid_t uid, gid_t gid);
bool supports_sdcardfs();
+long get_project_id(uid_t uid, long start_project_id_range);
+int set_quota_project_id(const std::string& path, long project_id, bool set_inherit);
int64_t get_occupied_app_space_external(const std::string& uuid, int32_t userId, int32_t appId);
int64_t get_occupied_app_cache_space_external(const std::string& uuid, int32_t userId, int32_t appId);
@@ -165,6 +184,10 @@
void drop_capabilities(uid_t uid);
+// Removes a file specified by a file descriptor. Returns true on success. Reports the file path to
+// `path` if present.
+bool remove_file_at_fd(int fd, /*out*/ std::string* path = nullptr);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
index 60d6492..8c000a1 100644
--- a/cmds/installd/view_compiler.cpp
+++ b/cmds/installd/view_compiler.cpp
@@ -33,7 +33,13 @@
namespace android {
namespace installd {
-using base::unique_fd;
+namespace {
+
+using ::android::base::unique_fd;
+
+constexpr int kTimeoutMs = 300000;
+
+} // namespace
bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
int uid) {
@@ -88,7 +94,17 @@
_exit(1);
}
- return wait_child(pid) == 0;
+ int return_code = wait_child_with_timeout(pid, kTimeoutMs);
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "viewcompiler failed for " << package_name << ":" << apk_path;
+ if (WTERMSIG(return_code) == SIGKILL) {
+ // If the subprocess is killed while it's writing to the file, the file is likely
+ // corrupted, so we should remove it.
+ remove_file_at_fd(outfd.get());
+ }
+ return false;
+ }
+ return WEXITSTATUS(return_code) == 0;
}
} // namespace installd
diff --git a/cmds/ip-up-vpn/Android.bp b/cmds/ip-up-vpn/Android.bp
new file mode 100644
index 0000000..c746f7f
--- /dev/null
+++ b/cmds/ip-up-vpn/Android.bp
@@ -0,0 +1,31 @@
+// Copyright 2011 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+ name: "ip-up-vpn",
+
+ srcs: ["ip-up-vpn.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+}
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
deleted file mode 100644
index 396ae9d..0000000
--- a/cmds/ip-up-vpn/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := ip-up-vpn.c
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_MODULE := ip-up-vpn
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 2722e21..ff73c94 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -28,6 +28,7 @@
#include <sstream>
#include <android-base/file.h>
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-hash/Hash.h>
@@ -691,8 +692,7 @@
}
auto&& hashArray = hashChain[hashIndex];
- std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
- entry->hash = Hash::hexString(hashVec);
+ entry->hash = android::base::HexString(hashArray.data(), hashArray.size());
});
if (!hashRet.isOk()) {
handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index bc99f4d..a5f98c2 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -142,12 +142,10 @@
}
}
- PipeRelay relay(out, err, interfaceName, instanceName);
-
- if (relay.initCheck() != OK) {
- std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
- err << msg << std::endl;
- LOG(ERROR) << msg;
+ auto relay = PipeRelay::create(out, err, interfaceName + "/" + instanceName);
+ if (!relay.ok()) {
+ err << "Unable to create PipeRelay: " << relay.error() << std::endl;
+ LOG(ERROR) << "Unable to create PipeRelay: " << relay.error();
return IO_ERROR;
}
@@ -155,7 +153,7 @@
native_handle_create(1 /* numFds */, 0 /* numInts */),
native_handle_delete);
- fdHandle->data[0] = relay.fd();
+ fdHandle->data[0] = relay.value()->fd().get();
hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 4e97636..863490d 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -16,143 +16,94 @@
#include "PipeRelay.h"
-#include <sys/select.h>
-#include <sys/time.h>
+#include <sys/poll.h>
#include <sys/types.h>
#include <unistd.h>
-#include <atomic>
+#include <chrono>
+#include <optional>
-#include <utils/Thread.h>
+#include <android-base/unique_fd.h>
+
+using android::base::borrowed_fd;
+using android::base::Result;
+using android::base::unique_fd;
+using std::chrono_literals::operator""ms;
namespace android {
namespace lshal {
-
-static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
-
-static std::string getThreadName(std::string interfaceName, const std::string &instanceName) {
- auto dot = interfaceName.rfind(".");
- if (dot != std::string::npos) interfaceName = interfaceName.substr(dot + 1);
- return "RelayThread_" + interfaceName + "_" + instanceName;
+Result<std::unique_ptr<PipeRelay>> PipeRelay::create(std::ostream& os,
+ const NullableOStream<std::ostream>& err,
+ const std::string& fqName) {
+ auto pipeRelay = std::unique_ptr<PipeRelay>(new PipeRelay());
+ unique_fd rfd;
+ if (!android::base::Pipe(&rfd, &pipeRelay->mWrite)) {
+ return android::base::ErrnoError() << "pipe()";
+ }
+ // Workaround for b/111997867: need a separate FD trigger because rfd can't receive POLLHUP
+ // when the write end is closed after the write end was sent through hwbinder.
+ unique_fd rfdTrigger;
+ if (!android::base::Pipe(&rfdTrigger, &pipeRelay->mWriteTrigger)) {
+ return android::base::ErrnoError() << "pipe() for trigger";
+ }
+ pipeRelay->mThread =
+ std::make_unique<std::thread>(&PipeRelay::thread, std::move(rfd), std::move(rfdTrigger),
+ &os, &err, fqName);
+ return pipeRelay;
}
-struct PipeRelay::RelayThread : public Thread {
- explicit RelayThread(int fd, std::ostream &os, const NullableOStream<std::ostream> &err,
- const std::string &fqName);
+void PipeRelay::thread(unique_fd rfd, unique_fd rfdTrigger, std::ostream* out,
+ const NullableOStream<std::ostream>* err, std::string fqName) {
+ while (true) {
+ pollfd pfd[2];
+ pfd[0] = {.fd = rfd.get(), .events = POLLIN};
+ pfd[1] = {.fd = rfdTrigger.get(), .events = 0};
- bool threadLoop() override;
- void setFinished();
-
-private:
- int mFd;
- std::ostream &mOutStream;
- NullableOStream<std::ostream> mErrStream;
-
- // If we were to use requestExit() and exitPending() instead, threadLoop()
- // may not run at all by the time ~PipeRelay is called (i.e. debug() has
- // returned from HAL). By using our own flag, we ensure that select() and
- // read() are executed until data are drained.
- std::atomic_bool mFinished;
-
- std::string mFqName;
-
- DISALLOW_COPY_AND_ASSIGN(RelayThread);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os,
- const NullableOStream<std::ostream> &err,
- const std::string &fqName)
- : mFd(fd), mOutStream(os), mErrStream(err), mFinished(false), mFqName(fqName) {}
-
-bool PipeRelay::RelayThread::threadLoop() {
- char buffer[1024];
-
- fd_set set;
- FD_ZERO(&set);
- FD_SET(mFd, &set);
-
- struct timeval timeout = READ_TIMEOUT;
-
- int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
- if (res < 0) {
- mErrStream << "debug " << mFqName << ": select() failed";
- return false;
- }
-
- if (res == 0 || !FD_ISSET(mFd, &set)) {
- if (mFinished) {
- mErrStream << "debug " << mFqName
- << ": timeout reading from pipe, output may be truncated.";
- return false;
+ int pollRes = poll(pfd, arraysize(pfd), -1 /* infinite timeout */);
+ if (pollRes < 0) {
+ int savedErrno = errno;
+ (*err) << "debug " << fqName << ": poll() failed: " << strerror(savedErrno)
+ << std::endl;
+ break;
}
- // timeout, but debug() has not returned, so wait for HAL to finish.
- return true;
- }
- // FD_ISSET(mFd, &set) == true. Data available, start reading
- ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
-
- if (n < 0) {
- mErrStream << "debug " << mFqName << ": read() failed";
- }
-
- if (n <= 0) {
- return false;
- }
-
- mOutStream.write(buffer, n);
-
- return true;
-}
-
-void PipeRelay::RelayThread::setFinished() {
- mFinished = true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-PipeRelay::PipeRelay(std::ostream &os, const NullableOStream<std::ostream> &err,
- const std::string &interfaceName, const std::string &instanceName)
- : mInitCheck(NO_INIT) {
- int res = pipe(mFds);
-
- if (res < 0) {
- mInitCheck = -errno;
- return;
- }
-
- mThread = new RelayThread(mFds[0], os, err, interfaceName + "/" + instanceName);
- mInitCheck = mThread->run(getThreadName(interfaceName, instanceName).c_str());
-}
-
-void PipeRelay::CloseFd(int *fd) {
- if (*fd >= 0) {
- close(*fd);
- *fd = -1;
+ if (pfd[0].revents & POLLIN) {
+ char buffer[1024];
+ ssize_t n = TEMP_FAILURE_RETRY(read(rfd.get(), buffer, sizeof(buffer)));
+ if (n < 0) {
+ int savedErrno = errno;
+ (*err) << "debug " << fqName << ": read() failed: " << strerror(savedErrno)
+ << std::endl;
+ break;
+ }
+ if (n == 0) {
+ (*err) << "Warning: debug " << fqName << ": poll() indicates POLLIN but no data"
+ << std::endl;
+ continue;
+ }
+ out->write(buffer, n);
+ continue;
+ }
+ if (pfd[0].revents & POLLHUP) {
+ break;
+ }
+ if (pfd[1].revents & POLLHUP) {
+ // ~PipeRelay is called on the main thread. |mWrite| has been flushed and closed.
+ // Ensure that our read end of the pipe doesn't have pending data, then exit.
+ if ((pfd[0].revents & POLLIN) == 0) {
+ break;
+ }
+ }
}
}
PipeRelay::~PipeRelay() {
- CloseFd(&mFds[1]);
-
- if (mThread != nullptr) {
- mThread->setFinished();
+ mWrite.reset();
+ mWriteTrigger.reset();
+ if (mThread != nullptr && mThread->joinable()) {
mThread->join();
- mThread.clear();
}
-
- CloseFd(&mFds[0]);
}
-status_t PipeRelay::initCheck() const {
- return mInitCheck;
-}
-
-int PipeRelay::fd() const {
- return mFds[1];
-}
-
-} // namespace lshal
-} // namespace android
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index bd994b4..45ba982 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -16,42 +16,43 @@
#pragma once
+#include <thread>
+
#include <android-base/macros.h>
-#include <ostream>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <ostream>
#include "NullableOStream.h"
namespace android {
namespace lshal {
-/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+/**
+ * Creates a pipe and spawns a thread that relays any data
* written to the "write"-end of the pair to the specified output stream "os".
*/
struct PipeRelay {
- explicit PipeRelay(std::ostream& os,
- const NullableOStream<std::ostream>& err,
- const std::string& interfaceName,
- const std::string& instanceName);
+ static android::base::Result<std::unique_ptr<PipeRelay>> create(
+ std::ostream& os, const NullableOStream<std::ostream>& err, const std::string& fqName);
~PipeRelay();
- status_t initCheck() const;
-
// Returns the file descriptor corresponding to the "write"-end of the
// connection.
- int fd() const;
+ android::base::borrowed_fd fd() const { return mWrite; }
private:
- struct RelayThread;
-
- status_t mInitCheck;
- int mFds[2];
- sp<RelayThread> mThread;
-
- static void CloseFd(int *fd);
-
+ PipeRelay() = default;
DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+ static void thread(android::base::unique_fd rfd, android::base::unique_fd rfdTrigger,
+ std::ostream* out, const NullableOStream<std::ostream>* err,
+ std::string fqName);
+
+ android::base::unique_fd mWrite;
+ android::base::unique_fd mWriteTrigger;
+ std::unique_ptr<std::thread> mThread;
};
} // namespace lshal
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index 8e21975..1753343 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -18,6 +18,7 @@
#include <map>
+#include <android-base/hex.h>
#include <android-base/strings.h>
#include <hidl-hash/Hash.h>
#include <vintf/parse_string.h>
@@ -104,7 +105,8 @@
}
std::string TableEntry::isReleased() const {
- static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+ static const std::string unreleased = android::base::HexString(Hash::kEmptyHash.data(),
+ Hash::kEmptyHash.size());
if (hash.empty()) {
return "?";
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 6f08f74..cba7c4b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -22,9 +22,10 @@
#include <thread>
#include <vector>
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
+#include <android-base/parseint.h>
#include <android/hardware/tests/inheritance/1.0/IChild.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <hidl/HidlTransportSupport.h>
#include <vintf/parse_xml.h>
@@ -77,6 +78,13 @@
content += "\n";
content += option.c_str();
}
+ if (options.size() > 0) {
+ uint64_t len;
+ if (android::base::ParseUint(options[0], &len)) {
+ content += "\n";
+ content += std::string(len, 'X');
+ }
+ }
ssize_t written = write(fd, content.c_str(), content.size());
if (written != (ssize_t)content.size()) {
LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
@@ -189,6 +197,16 @@
EXPECT_THAT(err.str(), HasSubstr("does not exist"));
}
+TEST_F(DebugTest, DebugLarge) {
+ EXPECT_EQ(0u, callMain(lshal, {
+ "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "10000"
+ }));
+ EXPECT_THAT(out.str(),
+ StrEq("android.hardware.tests.inheritance@1.0::IChild\n10000\n" +
+ std::string(10000, 'X')));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
TEST_F(DebugTest, DebugParent) {
EXPECT_EQ(0u, callMain(lshal, {
"lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.rc b/cmds/rss_hwm_reset/rss_hwm_reset.rc
index fbbc820..271cbf8 100644
--- a/cmds/rss_hwm_reset/rss_hwm_reset.rc
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.rc
@@ -18,7 +18,7 @@
oneshot
user nobody
group nobody readproc
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
capabilities DAC_OVERRIDE
on property:sys.rss_hwm_reset.on=1
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index 3e8e3f6..21ac11b 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -52,3 +52,21 @@
"-Werror",
],
}
+
+cc_binary_host {
+ name: "aservice",
+
+ srcs: ["service.cpp"],
+
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-DXP_UNIX",
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 18b6b58..d5ca725 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -21,6 +21,7 @@
#include <cutils/ashmem.h>
#include <getopt.h>
+#include <libgen.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -45,37 +46,14 @@
}
}
-// get the name of the generic interface we hold a reference to
-static String16 get_interface_name(sp<IBinder> service)
-{
- if (service != nullptr) {
- Parcel data, reply;
- status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
- if (err == NO_ERROR) {
- return reply.readString16();
- }
- }
- return String16();
-}
-
-static String8 good_old_string(const String16& src)
-{
- String8 name8;
- char ch8[2];
- ch8[1] = 0;
- for (unsigned j = 0; j < src.size(); j++) {
- char16_t ch = src[j];
- if (ch < 128) ch8[0] = (char)ch;
- name8.append(ch8);
- }
- return name8;
-}
-
int main(int argc, char* const argv[])
{
bool wantsUsage = false;
int result = 0;
+ /* Strip path off the program name. */
+ char* prog_name = basename(argv[0]);
+
while (1) {
int ic = getopt(argc, argv, "h?");
if (ic < 0)
@@ -87,7 +65,7 @@
wantsUsage = true;
break;
default:
- aerr << "service: Unknown option -" << ic << endl;
+ aerr << prog_name << ": Unknown option -" << ic << endl;
wantsUsage = true;
result = 10;
break;
@@ -96,10 +74,13 @@
#ifdef VENDORSERVICES
ProcessState::initWithDriver("/dev/vndbinder");
#endif
+#ifndef __ANDROID__
+ setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
+#endif
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if (sm == nullptr) {
- aerr << "service: Unable to get default service manager!" << endl;
+ aerr << prog_name << ": Unable to get default service manager!" << endl;
return 20;
}
@@ -113,7 +94,7 @@
aout << "Service " << argv[optind] <<
(service == nullptr ? ": not found" : ": found") << endl;
} else {
- aerr << "service: No service specified for check" << endl;
+ aerr << prog_name << ": No service specified for check" << endl;
wantsUsage = true;
result = 10;
}
@@ -125,8 +106,8 @@
String16 name = services[i];
sp<IBinder> service = sm->checkService(name);
aout << i
- << "\t" << good_old_string(name)
- << ": [" << good_old_string(get_interface_name(service)) << "]"
+ << "\t" << name
+ << ": [" << (service ? service->getInterfaceDescriptor() : String16()) << "]"
<< endl;
}
} else if (strcmp(argv[optind], "call") == 0) {
@@ -134,10 +115,11 @@
if (optind+1 < argc) {
int serviceArg = optind;
sp<IBinder> service = sm->checkService(String16(argv[optind++]));
- String16 ifName = get_interface_name(service);
+ String16 ifName = (service ? service->getInterfaceDescriptor() : String16());
int32_t code = atoi(argv[optind++]);
if (service != nullptr && ifName.size() > 0) {
Parcel data, reply;
+ data.markForBinder(service);
// the interface name is first
data.writeInterfaceToken(ifName);
@@ -147,7 +129,7 @@
if (strcmp(argv[optind], "i32") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no integer supplied for 'i32'" << endl;
+ aerr << prog_name << ": no integer supplied for 'i32'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -156,7 +138,7 @@
} else if (strcmp(argv[optind], "i64") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no integer supplied for 'i64'" << endl;
+ aerr << prog_name << ": no integer supplied for 'i64'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -165,7 +147,7 @@
} else if (strcmp(argv[optind], "s16") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no string supplied for 's16'" << endl;
+ aerr << prog_name << ": no string supplied for 's16'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -174,7 +156,7 @@
} else if (strcmp(argv[optind], "f") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no number supplied for 'f'" << endl;
+ aerr << prog_name << ": no number supplied for 'f'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -183,7 +165,7 @@
} else if (strcmp(argv[optind], "d") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no number supplied for 'd'" << endl;
+ aerr << prog_name << ": no number supplied for 'd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -195,7 +177,7 @@
} else if (strcmp(argv[optind], "fd") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no path supplied for 'fd'" << endl;
+ aerr << prog_name << ": no path supplied for 'fd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -203,7 +185,7 @@
const char *path = argv[optind++];
int fd = open(path, O_RDONLY);
if (fd < 0) {
- aerr << "service: could not open '" << path << "'" << endl;
+ aerr << prog_name << ": could not open '" << path << "'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -212,7 +194,7 @@
} else if (strcmp(argv[optind], "afd") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no path supplied for 'afd'" << endl;
+ aerr << prog_name << ": no path supplied for 'afd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -221,7 +203,8 @@
int fd = open(path, O_RDONLY);
struct stat statbuf;
if (fd < 0 || fstat(fd, &statbuf) != 0) {
- aerr << "service: could not open or stat '" << path << "'" << endl;
+ aerr << prog_name << ": could not open or stat"
+ << " '" << path << "'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -229,13 +212,14 @@
int afd = ashmem_create_region("test", statbuf.st_size);
void* ptr = mmap(NULL, statbuf.st_size,
PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
- read(fd, ptr, statbuf.st_size);
+ (void)read(fd, ptr, statbuf.st_size);
close(fd);
data.writeFileDescriptor(afd, true /* take ownership */);
} else if (strcmp(argv[optind], "nfd") == 0) {
optind++;
if (optind >= argc) {
- aerr << "service: no file descriptor supplied for 'nfd'" << endl;
+ aerr << prog_name << ": no file descriptor supplied for"
+ << " 'nfd'" << endl;
wantsUsage = true;
result = 10;
break;
@@ -322,7 +306,7 @@
// for now just set the extra field to be null.
data.writeInt32(-1);
} else {
- aerr << "service: unknown option " << argv[optind] << endl;
+ aerr << prog_name << ": unknown option " << argv[optind] << endl;
wantsUsage = true;
result = 10;
break;
@@ -332,44 +316,44 @@
service->transact(code, data, &reply);
aout << "Result: " << reply << endl;
} else {
- aerr << "service: Service " << argv[serviceArg]
+ aerr << prog_name << ": Service " << argv[serviceArg]
<< " does not exist" << endl;
result = 10;
}
} else {
if (optind < argc) {
- aerr << "service: No service specified for call" << endl;
+ aerr << prog_name << ": No service specified for call" << endl;
} else {
- aerr << "service: No code specified for call" << endl;
+ aerr << prog_name << ": No code specified for call" << endl;
}
wantsUsage = true;
result = 10;
}
} else {
- aerr << "service: Unknown command " << argv[optind] << endl;
+ aerr << prog_name << ": Unknown command " << argv[optind] << endl;
wantsUsage = true;
result = 10;
}
}
if (wantsUsage) {
- aout << "Usage: service [-h|-?]\n"
- " service list\n"
- " service check SERVICE\n"
- " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
- " | fd f | nfd n | afd f ] ...\n"
+ aout << "Usage: " << prog_name << " [-h|-?]\n"
+ " " << prog_name << " list\n"
+ " " << prog_name << " check SERVICE\n"
+ " " << prog_name << " call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR"
+ " | null | fd f | nfd n | afd f ] ...\n"
"Options:\n"
" i32: Write the 32-bit integer N into the send parcel.\n"
" i64: Write the 64-bit integer N into the send parcel.\n"
- " f: Write the 32-bit single-precision number N into the send parcel.\n"
- " d: Write the 64-bit double-precision number N into the send parcel.\n"
+ " f: Write the 32-bit single-precision number N into the send parcel.\n"
+ " d: Write the 64-bit double-precision number N into the send parcel.\n"
" s16: Write the UTF-16 string STR into the send parcel.\n"
" null: Write a null binder into the send parcel.\n"
- " fd: Write a file descriptor for the file f to the send parcel.\n"
- " nfd: Write file descriptor n to the send parcel.\n"
- " afd: Write an ashmem file descriptor for a region containing the data from"
- " file f to the send parcel.\n";
-// " intent: Write and Intent int the send parcel. ARGS can be\n"
+ " fd: Write a file descriptor for the file f into the send parcel.\n"
+ " nfd: Write the file descriptor n into the send parcel.\n"
+ " afd: Write an ashmem file descriptor for a region containing the data from\n"
+ " file f into the send parcel.\n";
+// " intent: Write an Intent into the send parcel. ARGS can be\n"
// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
return result;
}
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 3ebdeee..32922ca 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -47,6 +47,23 @@
}
cc_binary {
+ name: "servicemanager.microdroid",
+ defaults: ["servicemanager_defaults"],
+ init_rc: ["servicemanager.microdroid.rc"],
+ srcs: ["main.cpp"],
+ bootstrap: true,
+}
+
+cc_binary {
+ name: "servicemanager.recovery",
+ stem: "servicemanager",
+ recovery: true,
+ defaults: ["servicemanager_defaults"],
+ init_rc: ["servicemanager.recovery.rc"],
+ srcs: ["main.cpp"],
+}
+
+cc_binary {
name: "vndservicemanager",
defaults: ["servicemanager_defaults"],
init_rc: ["vndservicemanager.rc"],
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 90db509..3cfe529 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -28,6 +28,9 @@
#ifndef VENDORSERVICEMANAGER
#include <vintf/VintfObject.h>
+#ifdef __ANDROID_RECOVERY__
+#include <vintf/VintfObjectRecovery.h>
+#endif // __ANDROID_RECOVERY__
#include <vintf/constants.h>
#endif // !VENDORSERVICEMANAGER
@@ -37,16 +40,33 @@
namespace android {
#ifndef VENDORSERVICEMANAGER
+
struct ManifestWithDescription {
std::shared_ptr<const vintf::HalManifest> manifest;
const char* description;
};
+static std::vector<ManifestWithDescription> GetManifestsWithDescription() {
+#ifdef __ANDROID_RECOVERY__
+ auto vintfObject = vintf::VintfObjectRecovery::GetInstance();
+ if (vintfObject == nullptr) {
+ LOG(ERROR) << "NULL VintfObjectRecovery!";
+ return {};
+ }
+ return {ManifestWithDescription{vintfObject->getRecoveryHalManifest(), "recovery"}};
+#else
+ auto vintfObject = vintf::VintfObject::GetInstance();
+ if (vintfObject == nullptr) {
+ LOG(ERROR) << "NULL VintfObject!";
+ return {};
+ }
+ return {ManifestWithDescription{vintfObject->getDeviceHalManifest(), "device"},
+ ManifestWithDescription{vintfObject->getFrameworkHalManifest(), "framework"}};
+#endif
+}
+
// func true -> stop search and forEachManifest will return true
static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) {
- for (const ManifestWithDescription& mwd : {
- ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
- ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
- }) {
+ for (const ManifestWithDescription& mwd : GetManifestsWithDescription()) {
if (mwd.manifest == nullptr) {
LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
// note, we explicitly do not retry here, so that we can detect VINTF
@@ -93,8 +113,8 @@
if (!found) {
// Although it is tested, explicitly rebuilding qualified name, in case it
// becomes something unexpected.
- LOG(ERROR) << "Could not find " << aname.package << "." << aname.iface << "/"
- << aname.instance << " in the VINTF manifest.";
+ LOG(INFO) << "Could not find " << aname.package << "." << aname.iface << "/"
+ << aname.instance << " in the VINTF manifest.";
}
return found;
@@ -121,6 +141,35 @@
return updatableViaApex;
}
+static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) {
+ AidlName aname;
+ if (!AidlName::fill(name, &aname)) return std::nullopt;
+
+ std::optional<std::string> ip;
+ std::optional<uint64_t> port;
+ 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;
+ ip = manifestInstance.ip();
+ port = manifestInstance.port();
+ return false; // break (libvintf uses opposite convention)
+ });
+ return false; // continue
+ });
+
+ if (ip.has_value() && port.has_value()) {
+ ConnectionInfo info;
+ info.ipAddress = *ip;
+ info.port = *port;
+ return std::make_optional<ConnectionInfo>(info);
+ } else {
+ return std::nullopt;
+ }
+}
+
static std::vector<std::string> getVintfInstances(const std::string& interface) {
size_t lastDot = interface.rfind('.');
if (lastDot == std::string::npos) {
@@ -246,28 +295,27 @@
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto ctx = mAccess->getCallingContext();
- // apps cannot add services
if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
- return Status::fromExceptionCode(Status::EX_SECURITY);
+ return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services");
}
if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY);
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");
}
if (binder == nullptr) {
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder");
}
if (!isValidServiceName(name)) {
LOG(ERROR) << "Invalid service name: " << name;
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");
}
#ifndef VENDORSERVICEMANAGER
if (!meetsDeclarationRequirements(binder, name)) {
// already logged
- return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error");
}
#endif // !VENDORSERVICEMANAGER
@@ -275,7 +323,7 @@
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);
+ return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
// Overwrite the old service if it exists
@@ -437,6 +485,22 @@
return Status::ok();
}
+Status ServiceManager::getConnectionInfo(const std::string& name,
+ std::optional<ConnectionInfo>* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ *outReturn = std::nullopt;
+
+#ifndef VENDORSERVICEMANAGER
+ *outReturn = getVintfConnectionInfo(name);
+#endif
+ return Status::ok();
+}
+
void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 4f23c21..5e40319 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -24,6 +24,7 @@
namespace android {
+using os::ConnectionInfo;
using os::IClientCallback;
using os::IServiceCallback;
using os::ServiceDebugInfo;
@@ -48,6 +49,8 @@
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 getConnectionInfo(const std::string& name,
+ std::optional<ConnectionInfo>* 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 8c1beac..2fb9c2b 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -111,6 +111,10 @@
};
int main(int argc, char** argv) {
+#ifdef __ANDROID_RECOVERY__
+ android::base::InitLogging(argv, android::base::KernelLogger);
+#endif
+
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
}
diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc
new file mode 100644
index 0000000..e01f132
--- /dev/null
+++ b/cmds/servicemanager/servicemanager.microdroid.rc
@@ -0,0 +1,8 @@
+service servicemanager /system/bin/servicemanager.microdroid
+ class core
+ user system
+ group system readproc
+ critical
+ onrestart restart apexd
+ task_profiles ServiceCapacityLow
+ shutdown critical
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 6d5070f..e5d689f 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -6,8 +6,8 @@
onrestart restart apexd
onrestart restart audioserver
onrestart restart gatekeeperd
- onrestart class_restart main
- onrestart class_restart hal
- onrestart class_restart early_hal
- writepid /dev/cpuset/system-background/tasks
+ onrestart class_restart --only-enabled main
+ onrestart class_restart --only-enabled hal
+ onrestart class_restart --only-enabled early_hal
+ task_profiles ServiceCapacityLow
shutdown critical
diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc
new file mode 100644
index 0000000..067faf9
--- /dev/null
+++ b/cmds/servicemanager/servicemanager.recovery.rc
@@ -0,0 +1,4 @@
+service servicemanager /system/bin/servicemanager
+ disabled
+ group system readproc
+ seclabel u:r:servicemanager:s0
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index 756f6c3..c9305a1 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -2,7 +2,7 @@
class core
user system
group system readproc
- writepid /dev/cpuset/system-background/tasks
+ task_profiles ServiceCapacityLow
onrestart class_restart main
onrestart class_restart hal
onrestart class_restart early_hal
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index c0cbad8..c901c59 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -7,12 +7,253 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+prebuilt_defaults {
+ name: "frameworks_native_data_etc_defaults",
+ relative_install_path: "permissions",
+ soc_specific: true,
+}
+
+// Modules use the 'prebuilt.xml' suffix to prevent conflicting
+// overridden paths, so that this Android.bp can exist alongside
+// devices that use PRODUCT_COPY_FILES for these files.
+//
+// This override prevention is also possible using a soong_namespace,
+// but that requires every dependent module (e.g. an APEX that includes
+// one of these files) to also reference this namespace, and so on
+// for all dependent modules. It is simpler to just use new path names.
+
prebuilt_etc {
- name: "android.hardware.biometrics.face.xml",
- product_specific: true,
- sub_dir: "permissions",
+ name: "android.hardware.audio.low_latency.prebuilt.xml",
+ src: "android.hardware.audio.low_latency.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.biometrics.face.prebuilt.xml",
src: "android.hardware.biometrics.face.xml",
- filename_from_src: true,
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth_le.prebuilt.xml",
+ src: "android.hardware.bluetooth_le.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth.prebuilt.xml",
+ src: "android.hardware.bluetooth.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.concurrent.prebuilt.xml",
+ src: "android.hardware.camera.concurrent.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.flash-autofocus.prebuilt.xml",
+ src: "android.hardware.camera.flash-autofocus.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.front.prebuilt.xml",
+ src: "android.hardware.camera.front.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.full.prebuilt.xml",
+ src: "android.hardware.camera.full.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.camera.raw.prebuilt.xml",
+ src: "android.hardware.camera.raw.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.ethernet.prebuilt.xml",
+ src: "android.hardware.ethernet.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.faketouch.prebuilt.xml",
+ src: "android.hardware.faketouch.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.fingerprint.prebuilt.xml",
+ src: "android.hardware.fingerprint.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.location.gps.prebuilt.xml",
+ src: "android.hardware.location.gps.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.reboot_escrow.prebuilt.xml",
+ src: "android.hardware.reboot_escrow.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.ambient_temperature.prebuilt.xml",
+ src: "android.hardware.sensor.ambient_temperature.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.barometer.prebuilt.xml",
+ src: "android.hardware.sensor.barometer.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.gyroscope.prebuilt.xml",
+ src: "android.hardware.sensor.gyroscope.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.hinge_angle.prebuilt.xml",
+ src: "android.hardware.sensor.hinge_angle.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.light.prebuilt.xml",
+ src: "android.hardware.sensor.light.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.proximity.prebuilt.xml",
+ src: "android.hardware.sensor.proximity.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.sensor.relative_humidity.prebuilt.xml",
+ src: "android.hardware.sensor.relative_humidity.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.telephony.gsm.prebuilt.xml",
+ src: "android.hardware.telephony.gsm.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.telephony.ims.prebuilt.xml",
+ src: "android.hardware.telephony.ims.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.usb.accessory.prebuilt.xml",
+ src: "android.hardware.usb.accessory.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.usb.host.prebuilt.xml",
+ src: "android.hardware.usb.host.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.vulkan.level-0.prebuilt.xml",
+ src: "android.hardware.vulkan.level-0.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.vulkan.version-1_0_3.prebuilt.xml",
+ src: "android.hardware.vulkan.version-1_0_3.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.wifi.prebuilt.xml",
+ src: "android.hardware.wifi.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.wifi.direct.prebuilt.xml",
+ src: "android.hardware.wifi.direct.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.hardware.wifi.passpoint.prebuilt.xml",
+ src: "android.hardware.wifi.passpoint.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.device_id_attestation.prebuilt.xml",
+ src: "android.software.device_id_attestation.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.ipsec_tunnels.prebuilt.xml",
+ src: "android.software.ipsec_tunnels.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.opengles.deqp.level-2021-03-01.prebuilt.xml",
+ src: "android.software.opengles.deqp.level-2021-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.sip.voip.prebuilt.xml",
+ src: "android.software.sip.voip.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.verified_boot.prebuilt.xml",
+ src: "android.software.verified_boot.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "android.software.vulkan.deqp.level-2021-03-01.prebuilt.xml",
+ src: "android.software.vulkan.deqp.level-2021-03-01.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "aosp_excluded_hardware.prebuilt.xml",
+ src: "aosp_excluded_hardware.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "go_handheld_core_hardware.prebuilt.xml",
+ src: "go_handheld_core_hardware.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+ name: "handheld_core_hardware.prebuilt.xml",
+ src: "handheld_core_hardware.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
}
prebuilt_etc {
diff --git a/data/etc/android.software.opengles.deqp.level-2022-03-01.xml b/data/etc/android.software.opengles.deqp.level-2022-03-01.xml
new file mode 100644
index 0000000..0a11835
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2022-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+ dEQP tests associated with date 2022-03-01 (0x07E60301). -->
+<permissions>
+ <feature name="android.software.opengles.deqp.level" version="132514561" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml
new file mode 100644
index 0000000..8deebc0
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+ tests associated with date 2022-03-01 (0x07E60301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132514561" />
+</permissions>
diff --git a/data/etc/apex/Android.bp b/data/etc/apex/Android.bp
new file mode 100644
index 0000000..8c4929c
--- /dev/null
+++ b/data/etc/apex/Android.bp
@@ -0,0 +1,34 @@
+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"],
+}
+
+apex_key {
+ name: "com.android.hardware.core_permissions.key",
+ public_key: "com.android.hardware.core_permissions.avbpubkey",
+ private_key: "com.android.hardware.core_permissions.pem",
+}
+
+android_app_certificate {
+ name: "com.android.hardware.core_permissions.certificate",
+ certificate: "com.android.hardware.core_permissions",
+}
+
+apex {
+ name: "com.android.hardware.core_permissions",
+ manifest: "apex_manifest.json",
+ key: "com.android.hardware.core_permissions.key",
+ certificate: ":com.android.hardware.core_permissions.certificate",
+ file_contexts: "file_contexts",
+ updatable: false,
+ // Install the apex in /vendor/apex
+ soc_specific: true,
+ prebuilts: [
+ "handheld_core_hardware.prebuilt.xml",
+ "aosp_excluded_hardware.prebuilt.xml",
+ ],
+}
diff --git a/data/etc/apex/apex_manifest.json b/data/etc/apex/apex_manifest.json
new file mode 100644
index 0000000..5bbf229
--- /dev/null
+++ b/data/etc/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.core_permissions",
+ "version": 1
+}
diff --git a/data/etc/apex/com.android.hardware.core_permissions.avbpubkey b/data/etc/apex/com.android.hardware.core_permissions.avbpubkey
new file mode 100644
index 0000000..b9164fb
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.avbpubkey
Binary files differ
diff --git a/data/etc/apex/com.android.hardware.core_permissions.pem b/data/etc/apex/com.android.hardware.core_permissions.pem
new file mode 100644
index 0000000..7e2826d
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAuJjZgFCp6uX+xgKET1FsXYqEPGfYEWUWJ4VSP+Y5fgth/Om3
+XCRBhKSD4CPyL/E9ohh7eSLRqIzw/idUazgCqk+yYLiVkYZiuY02jcui1/Vze9er
+Nwi0ZSwA+zcvKCEOwZ3PBT6W1kehiQ5PU0IS+78po8LoUrvycmvbXJTHlVt1x2bo
+y2DQmxRjIH9xfACwFwh/JnKyr1O2NGjFbk+z3CYx9l7c0Ew9U/kGL3teSbMEi1le
+2PApAHYUA+kXiwjF07aRUN+zzSdZsI7goQXEsmqGXNy7Fzdp/UDocayBmCdI3a35
+igcPRUryBIf1YdSS+E9DwoXRR7pwzs4ajvVTrzuv7UohTnhPwj95TD0E3Z64r7S7
+AT4jtm9gbkAsKNkKOqioGTEIdmvj2prOA4wOUmVBGwOjGcjsyEPJaa56s0WEXUop
++OD2ZMV3StAIwQ5c/gpFzxWl+qATv3MH9MgwAIjT1TDyXv0R+q9JbFbgTtO748RS
+MZUb1i2odggNQCWRtv8fqJ7c51H7pUpHXCXElXHysFq2oBOY4J1jXr1craxsPn1P
+RcImVwAYTV80jOfmYtWhdJhDavDeD4uinLw+4HeZnFNwZXqCJl0LtLxMDRxoDCr7
+YgT2znh9BM6XXg8jekfkDYb5wyloU1eOZJMxF04pGecDB9n1w/OFBA4v0WECAwEA
+AQKCAgEArjhsRsNaqvzo6L7lWurxCJO73Drx3PD36NLWXsKNjl113LpEOO1q/KI8
+aKXkZMUdM0hB+IEZOSfUJzq9XPge49iV9N0hJJidwpv5WfhQN9xLYx2YVTec8kOG
+pZJeqlQQ1kF3am6484HlfjIIQf8BZaH0zb8df0AtQTp0bTtp5pfMYCbLHW/BUiv6
+pmhBlhQcHZECWCo2ZGzwcSRU+Zi1mthdnTXI17qswv0rjlK0GYCgkFgHwV1ghTPs
+DgjHFIxyES+klJyc2MoDxzQB41dLXkxVhX06Al5lZQUGnIqAQTcKeVZCRrgE/JQQ
+OKCMwglbsIk23XdonnbjEvvIaxY1JHjcnPBpOC4+O11fE0DiHXK3GBj5KlfVvB5D
+oMWko3R/Ky/T/KJhHYXbC1H71oYueCaY57kHFKk2k3qRJG4DU4MY20cfUZ0vp14H
+KJ++gDy0pxxjl4ZUiryBCti5k5GPU8Mm46MLJ/YPdX6Dj1nMtOgGpZkGQYIKPhEI
+qZjZBRyZlHeTJsTMc8Eh3/Krimmra5ID95HfJnTTHHshbRcLwL6/zMTU5fkwarsC
+f4HQ0602/9HqyI8Ty1S9Z4oByjwfW2uDcosnuOPfk/8XwfLWxrf2+TsAd3cXhOKw
+rwUfELzcgYNueLGTJOCsEJfo8NIIEGJCNSgMnWXmIAUIAlrMP8ECggEBAOt9X4Lb
+fkrQLjcQ+K1oOI0Q+43htNRYXiG2IDhmDlA+UnqPP+9j2cVyuo4QYhKTFXRbbezR
+blUHAowd4hKHtODaHMuq90KbeByVNB8idcIb+ELAOK4Ff+qd9ijrBIOuZZQB+KOo
+SlxVjy1LM0QGtUTJRHx4dkCmp+hMqrIc4LQOWd4hV5h85Oj8kp1L1eMvxEStUtwP
+tYR80OoOdDxgXcBHLdPs4rc0WunRabGE+cnCMrTy31D95OWg6aw/+XKSTUS5Hfdy
+4jDIwP8DR6JU71qNgen+fwrHFeDienM40sSpi85/WQndQW5TwOMbDlEfmgn6D4+s
+rVWqFk1XElfwwSkCggEBAMisvdv5fH4UeH+tz5cF5f3ZNY+NX8uj85wCsJAPaAVx
+i3t8BqEKUPA6FPt9SDMWg4QtgSSl0NmhH2F9CcAZUCiTZUrtgqyIo80ALONW1FR9
+ofElvZEeV2IzKn3Ci4HA2pKRtMcjjVLwxzdoHakbPS9CbdCGKYE3W75Huw410IW6
+gV4zQ2mWHT+FxXaatl6Arj0x7DHLeSrMV33uxcYWoclmrAK24uhq2gwhtC8U0SvY
+rtJ7+KpCRd5v3Cyzo2AEbZKyJYVKbMDu9RHDZwkZw6wVqaOKBPJVyC++yidksexX
+ZT0WGX0f23t+2jbbsNY6H27pJm9ApLuAYwiMGv9n/XkCggEADLlAcNyVLUukQ5tq
+JExuScjyHo9kati/dUjW4tU4zsMfR7n3tWKKwK1bQRPHiMNjtF7ASLxkHrn7PEDd
+Fy0367I9Pg/lvjaSPdEd+NSu0icaudiS92wapj2UsE9Kdib1HBMjMQyFwAlrbAIV
+KgbGwomxZpxHn2Shy95glrESvwfLeUIJ7pZI9AG5lkAjtVu+WguXX4aFwzvPOeZA
+B4cZaasu4bV55nYwt1N2R34s1ObmQHqi8EhXlsSj+4eVXchj3mO2J8mQSRx/uQef
+VjkKmbTtoQv8J0PsfbMe9JzMXo3enPCqiernfyONV3f9xQpVE1bsglHNJ8TB4bnj
+pta+SQKCAQEArDqNrFkAftkk3jgXnX9jeC3O6UilugoZj4FDdjCyz1E3LCEzM02+
+T58Z2QoaSDZ/Y5cGaqShjdbaLvp4vtU61chDPD6CU3/mTZBj9i3UiDtXHLeObhlD
+WDWft1WcFB2nufmx1OPvbArYf/Ys1rFZHtF9nGU5A/y2EaZQpY6MS+nZFDcdGWbL
+7XPrGLMJ6Cu63yyUkdwXPyMnyB6AwVU1P7yNzrqWHnFueNEIawwLxfzvdhkOP1on
+yxPoPLlkc4j5XdjlmPNaSXANB1TUfpwNMwlYkdJoEnCLImc16v9iMPyFGBt6fsgz
+wFcMA98jc4lo5vDVmtA5Ue+Lj49nsGLYyQKCAQEAoB21vLDm7sLcZhzHFnh7h3L0
+wLMFMyQ0QDMWOqrlABcME21CWhibu8XwouF+hHLKX9GjaBB3ujkyeun1x8MpGQwT
+1SrMVN4osHpFrCh85uK5mabsqC8YjICIncU1U1ykxDV9v7TXuXgMtUIMKPFcUQLv
+ckf/PNE1Fvt5ESn2GIxk+ibM0L2kzHgDFgwiPx+k8GmJt5VZSXwehPmH6jgyCBIv
+kPHos1Q/z2LtfdUZcGhwX88mBNBpk3UXjiU8qO+ddoXCRgbThFDqYvOcdacbKGc0
+upFMhNsTWocn7CW0rbzusTsTt6bSWCGas8f9G9CMNN6rp8SW7Qc04m6sXVjPbw==
+-----END RSA PRIVATE KEY-----
diff --git a/data/etc/apex/com.android.hardware.core_permissions.pk8 b/data/etc/apex/com.android.hardware.core_permissions.pk8
new file mode 100644
index 0000000..4497844
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.pk8
Binary files differ
diff --git a/data/etc/apex/com.android.hardware.core_permissions.x509.pem b/data/etc/apex/com.android.hardware.core_permissions.x509.pem
new file mode 100644
index 0000000..57a311d
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF7zCCA9cCFD7UZbcK7ZVyJegJvOs8e5T/n0DLMA0GCSqGSIb3DQEBCwUAMIGy
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEuMCwGA1UEAwwlY29t
+LmFuZHJvaWQuaGFyZHdhcmUuY29yZV9wZXJtaXNzaW9uczAgFw0yMTA4MjYyMDM2
+NTBaGA80NzU5MDcyMzIwMzY1MFowgbIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRy
+b2lkMRAwDgYDVQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFu
+ZHJvaWQuY29tMS4wLAYDVQQDDCVjb20uYW5kcm9pZC5oYXJkd2FyZS5jb3JlX3Bl
+cm1pc3Npb25zMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1ZGPs2s2
+R9/+jd3dHLH0nt4Z5WWduQ4Wqy6H9oojktTCv0IJekfiC6L0VHOvW9DKtSEGWTJg
+sJdoEpd2KDhNxAdjbE6k50AfKD0CAE0MAX2MyJIpUz7b6p6p7kxB7xpJohSGDOSZ
+otuMJ16W99PElwOtQr99Wztf+WehmEkKYDUVA0V3+UP3s0quAo3ZrFYgZxXy51YF
+/rcM+HFNrpBRNZRhm3n/2uM4vqt+HTjUFvPuxFIq44DH64ofD7OYBOTbq7rU3lFr
+jEP4IlVH1mjyirh0pWIzXtqhcj2yfV8HjqnwHz+DhIA7kI1hZNOTotTiYKZszboy
+mvo8YA+fuSDCohFxVJVHZGFu+FA+m353ZPLTDTee+d3F9JGbLxa3NoPAgDIyU/tR
+KD7+fKxfr32coZzf3bDi9T4CHBoHKoikRWqOAhkZ/xGvjX12bI6eS1QP9THGu3d6
+o+ZzSZDPR9GSu8ggFtkRGgaIIbgV3y4XUKqLK3+pyg14tHwqvSYMItZ7oOYKMT47
+R9qb8MlvAWS2ooZlJwSkGSM3y0pTwy3rKXug+Cpvx7zjc3Nm/srzdPAmrEvBTZZN
+k0J1oYKqiNHV1N3PIlMRE2d4g7MVF4GEwrAgL126JZOOmzefkP59eAPNrH6Coyka
+3pAVnifemHYZlhWpbKO6pnuxEwvBGXvJlgkCAwEAATANBgkqhkiG9w0BAQsFAAOC
+AgEAfc6TD6fURc9sKHn5TSi30rIlarR6h1TbxFL4PQroEXWafkNmOMujdyV6YZlZ
+j/lzU4ko+Pn3y1aU4r88PkrjkR2Ttf01H3wj8IkTVyl3kN3o/Ud2jJygL3SbjMS1
+CAxiotvPA3lst3KN3nnyFLe02EB4OIi8fS14/kUVFVz+djpGDhi/lJUzcTCzO1NR
+yoC3RuAHBrly1+0QYcXiRTtvgnXrUqsZery8pysR7OK8fWkJzQ6I6OipElrcRzfK
+qoRq/u7nn9FJxXauVjM5HNCPq1VsB8+/FQqP2CgvxNPtkxy8AkXS3hKMBC0Id0Mo
+sDsAr88QDnCb5DqrWSMDKTKA0k+2a6QwS72ANkK5Uq2Hf/xUVjn+yHLSFuo4pCYe
+TX4ZCjK8My+XPWEiHBV/AELAWA9SxxZFhHmyuPj3MwN5uJcPNPsQepnhpeGv0Dlp
+J7UfzkdAZvOyQ+9CAQfu8+e2MilLHC3uqfnGLpHGkcHoN93rmH1x14JdapKKk3XL
+4Wo0RzEjGQekjMF0topQSqDTukOMdtZ1T0WTVOstYLlNqlhn0ZVbwVANGklN/fDW
+d6OpayLPuuaLBAM6Ivnv7n4XA49ojd9Gw305Ha/ATEoH9KwImFjvUa4d9SkR0haP
+hAiGhpaWViEe2zXOpzLhePgqc2gJ/IO7vIgrVks0iVeBoWE=
+-----END CERTIFICATE-----
diff --git a/data/etc/apex/file_contexts b/data/etc/apex/file_contexts
new file mode 100644
index 0000000..6524a5e
--- /dev/null
+++ b/data/etc/apex/file_contexts
@@ -0,0 +1,2 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
diff --git a/docs/Doxyfile b/docs/Doxyfile
index a1bd960..ea22337 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1638,6 +1638,7 @@
"__attribute__(x)=" \
__ANDROID__ \
__BIONIC__ \
+ "U_IN_DOXYGEN=1" \ # Required by the ICU4C module only
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
diff --git a/include/android/input.h b/include/android/input.h
index bb98beb..7642215 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -947,9 +947,10 @@
* and {@link AMotionEvent_fromJava()}.
* After returning, the specified AInputEvent* object becomes invalid and should no longer be used.
* The underlying Java object remains valid and does not change its state.
+ *
+ * Available since API level 31.
*/
-
-void AInputEvent_release(const AInputEvent* event);
+void AInputEvent_release(const AInputEvent* event) __INTRODUCED_IN(31);
/*** Accessors for key events only. ***/
@@ -1001,8 +1002,10 @@
* Creates a native AInputEvent* object that is a copy of the specified Java android.view.KeyEvent.
* The result may be used with generic and KeyEvent-specific AInputEvent_* functions. The object
* returned by this function must be disposed using {@link AInputEvent_release()}.
+ *
+ * Available since API level 31.
*/
-const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent);
+const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent) __INTRODUCED_IN(31);
/*** Accessors for motion events only. ***/
@@ -1324,8 +1327,10 @@
* android.view.MotionEvent. The result may be used with generic and MotionEvent-specific
* AInputEvent_* functions. The object returned by this function must be disposed using
* {@link AInputEvent_release()}.
+ *
+ * Available since API level 31.
*/
-const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent);
+const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent) __INTRODUCED_IN(31);
struct AInputQueue;
/**
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 509ee0e..ee392fc 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -216,6 +216,79 @@
*/
void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
+/*
+ * Set the socket tag and owning UID for traffic statistics on the specified
+ * socket.
+ *
+ * Subsequent calls always replace any existing parameters. The socket tag and
+ * uid (if set) are kept when the socket is sent to another process using binder
+ * IPCs or other mechanisms such as UNIX socket fd passing. Any app can accept
+ * blame for future traffic performed on a socket originally created by another
+ * app by calling this method with its own UID (or calling
+ * android_tag_socket(int sockfd, int tag)). However, only apps holding the
+ * android.Manifest.permission#UPDATE_DEVICE_STATS permission may assign blame
+ * to another UIDs. If unset (default) the socket tag is 0, and the uid is the
+ * socket creator's uid.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Available since API level 33.
+ */
+int android_tag_socket_with_uid(int sockfd, uint32_t tag, uid_t uid) __INTRODUCED_IN(33);
+
+/*
+ * Set the socket tag for traffic statistics on the specified socket.
+ *
+ * This function tags the socket with the caller's UID (accepting blame for
+ * future traffic performed on this socket) even if the socket was originally
+ * opened by another UID or was previously tagged by another UID. Subsequent
+ * calls always replace any existing parameters. The socket tag is kept when the
+ * socket is sent to another process using binder IPCs or other mechanisms such
+ * as UNIX socket fd passing. The tag is a value defined by the caller and used
+ * together with uid for data traffic accounting, so that the function callers
+ * can account different types of data usage for a uid.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Some possible error codes:
+ * -EBADF Bad socketfd.
+ * -EPERM No permission.
+ * -EAFNOSUPPORT Socket family is neither AF_INET nor AF_INET6.
+ * -EPROTONOSUPPORT Socket protocol is neither IPPROTO_UDP nor IPPROTO_TCP.
+ * -EMFILE Too many stats entries.
+ * There are still other error codes that may provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF maps read/write sys calls, which are set appropriately.
+ *
+ * Available since API level 33.
+ */
+int android_tag_socket(int sockfd, uint32_t tag) __INTRODUCED_IN(33);
+
+/*
+ * Untag a network socket.
+ *
+ * Future traffic on this socket will no longer be associated with any
+ * previously configured tag and uid. If the socket was created by another UID
+ * or was previously tagged by another UID, calling this function will clear the
+ * statistics parameters, and thus the UID blamed for traffic on the socket will
+ * be the UID that originally created the socket, even if the socket was
+ * subsequently tagged by a different UID.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * One of possible error code:
+ * -EBADF Bad socketfd.
+ * Other error codes are either provided by -errno of
+ * [getsockopt()](https://man7.org/linux/man-pages/man2/getsockopt.2.html) or by
+ * BPF map element deletion sys call, which are set appropriately.
+ *
+ * Available since API level 33.
+ */
+int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_MULTINETWORK_H
diff --git a/include/android/storage_manager.h b/include/android/storage_manager.h
index 7f2ee08..270570e 100644
--- a/include/android/storage_manager.h
+++ b/include/android/storage_manager.h
@@ -124,6 +124,12 @@
/**
* Attempts to mount an OBB file. This is an asynchronous operation.
+ *
+ * Since API level 33, this function can only be used to mount unencrypted OBBs,
+ * i.e. the {@code key} parameter must be {@code null} or an empty string. Note
+ * that even before API level 33, mounting encrypted OBBs didn't work on many
+ * Android device implementations. Applications should not assume any particular
+ * behavior when {@code key} is nonempty.
*/
void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key,
AStorageManager_obbCallbackFunc cb, void* data);
diff --git a/include/binder/Enum.h b/include/binder/Enum.h
deleted file mode 100644
index 4c25654..0000000
--- a/include/binder/Enum.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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
-
-#error Do not rely on global include files. All Android cc_* programs are given access to \
- include_dirs for frameworks/native/include via global configuration, but this is legacy \
- configuration. Instead, you should have a direct dependency on libbinder OR one of your \
- dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h
index f50ff46..6e98fee 100644
--- a/include/ftl/NamedEnum.h
+++ b/include/ftl/NamedEnum.h
@@ -49,6 +49,10 @@
// Example (cont'd): V = android::test::TestEnums::ONE
view = view.substr(valStart);
+ // Check invalid enum values with cast, like V = (android::test::TestEnums)8.
+ if (view.find('(') != std::string::npos) {
+ return std::nullopt;
+ }
size_t nameStart = view.rfind("::");
if (nameStart == std::string::npos) {
return std::nullopt;
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index b74923c..ac3e5b8 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -42,12 +42,13 @@
cc_library {
name: "libandroid_runtime_lazy",
vendor_available: true,
+ recovery_available: true,
double_loadable: true,
host_supported: true,
target: {
darwin: {
enabled: false,
- }
+ },
},
cflags: [
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index ec697a0..63d87da 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -25,6 +25,7 @@
name: "libbinder_headers",
export_include_dirs: ["include"],
vendor_available: true,
+ recovery_available: true,
host_supported: true,
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
@@ -68,11 +69,14 @@
cc_library {
name: "libbinder",
+ version_script: "libbinder.map",
+
// for vndbinder
vendor_available: true,
vndk: {
enabled: true,
},
+ recovery_available: true,
double_loadable: true,
host_supported: true,
// TODO(b/153609531): remove when no longer needed.
@@ -96,6 +100,7 @@
"BpBinder.cpp",
"BufferedTextOutput.cpp",
"Debug.cpp",
+ "FdTrigger.cpp",
"IInterface.cpp",
"IMemory.cpp",
"IPCThreadState.cpp",
@@ -111,16 +116,15 @@
"ParcelFileDescriptor.cpp",
"PersistableBundle.cpp",
"ProcessState.cpp",
- "RpcAddress.cpp",
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
+ "RpcTransportRaw.cpp",
"Static.cpp",
"Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"Utils.cpp",
- ":packagemanager_aidl",
":libbinder_aidl",
],
@@ -133,56 +137,36 @@
enabled: false,
},
},
- android_arm64: {
- // b/189438896 Sampling PGO restricted to arm64, arm32 in sc-dev
- pgo: {
- sampling: true,
- profile_file: "libbinder/libbinder.profdata",
- },
- // b/189438896 Add exported symbols in a map file for ABI stability
- version_script: "libbinder.arm64.map",
- target: {
- vendor: {
- version_script: "libbinder.arm64.vendor.map",
- },
- },
- },
- android_arm: {
- // b/189438896 Sampling PGO restricted to arm64, arm32 in sc-dev
- pgo: {
- sampling: true,
- profile_file: "libbinder/libbinder.profdata",
- },
- // b/189438896 Add exported symbols in a map file for ABI stability
- version_script: "libbinder.arm32.map",
- target: {
- vendor: {
- version_script: "libbinder.arm32.vendor.map",
- },
- },
- },
vendor: {
exclude_srcs: libbinder_device_interface_sources,
},
darwin: {
enabled: false,
},
+ host: {
+ srcs: [
+ "ServiceManagerHost.cpp",
+ "UtilsHost.cpp",
+ ],
+ },
+ recovery: {
+ exclude_header_libs: [
+ "libandroid_runtime_vm_headers",
+ ],
+ },
},
aidl: {
export_aidl_headers: true,
},
- // TODO(b/142684679): for com.android.media which is compiled
- // as vendor and used as system code.
- use_apex_name_macro: true,
-
cflags: [
"-Wall",
"-Wextra",
"-Wextra-semi",
"-Werror",
"-Wzero-as-null-pointer-constant",
+ "-Wreorder-init-list",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
@@ -190,6 +174,10 @@
binder32bit: {
cflags: ["-DBINDER_IPC_32BIT=1"],
},
+
+ debuggable: {
+ cflags: ["-DBINDER_RPC_DEV_SERVERS"],
+ },
},
shared_libs: [
@@ -198,8 +186,13 @@
"libutils",
],
+ static_libs: [
+ "libbase",
+ ],
+
header_libs: [
"libbinder_headers",
+ "libandroid_runtime_vm_headers",
],
export_header_lib_headers: [
@@ -210,7 +203,6 @@
sanitize: {
misc_undefined: ["integer"],
},
- min_sdk_version: "29",
tidy: true,
tidy_flags: [
@@ -232,12 +224,64 @@
"performance*",
"portability*",
],
+
+ afdo: true,
+}
+
+cc_defaults {
+ name: "libbinder_tls_shared_deps",
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "liblog",
+ "libssl",
+ "libutils",
+ ],
+}
+
+cc_defaults {
+ name: "libbinder_tls_defaults",
+ defaults: ["libbinder_tls_shared_deps"],
+ host_supported: true,
+
+ header_libs: [
+ "libbinder_headers",
+ ],
+ export_header_lib_headers: [
+ "libbinder_headers",
+ ],
+ export_shared_lib_headers: [
+ "libssl",
+ ],
+ export_include_dirs: ["include_tls"],
+ static_libs: [
+ "libbase",
+ ],
+ srcs: [
+ "RpcTransportTls.cpp",
+ "RpcTlsUtils.cpp",
+ ],
+}
+
+cc_library_shared {
+ name: "libbinder_tls",
+ defaults: ["libbinder_tls_defaults"],
+}
+
+// For testing
+cc_library_static {
+ name: "libbinder_tls_static",
+ defaults: ["libbinder_tls_defaults"],
+ visibility: [
+ ":__subpackages__",
+ ],
}
// AIDL interface between libbinder and framework.jar
filegroup {
name: "libbinder_aidl",
srcs: [
+ "aidl/android/os/ConnectionInfo.aidl",
"aidl/android/os/IClientCallback.aidl",
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
@@ -246,14 +290,27 @@
path: "aidl",
}
-filegroup {
+aidl_interface {
name: "packagemanager_aidl",
+ unstable: true,
+ local_include_dir: "aidl",
+ host_supported: true,
srcs: [
"aidl/android/content/pm/IPackageChangeObserver.aidl",
"aidl/android/content/pm/IPackageManagerNative.aidl",
"aidl/android/content/pm/PackageChangeEvent.aidl",
+ "aidl/android/content/pm/IStagedApexObserver.aidl",
+ "aidl/android/content/pm/ApexStagedEvent.aidl",
+ "aidl/android/content/pm/StagedApexInfo.aidl",
],
- path: "aidl",
+ backend: {
+ rust: {
+ apex_available: [
+ "com.android.virt",
+ ],
+ enabled: true,
+ },
+ },
}
aidl_interface {
@@ -269,6 +326,36 @@
},
}
+// TODO(b/184872979): remove once the Rust API is created.
+cc_library {
+ name: "libbinder_rpc_unstable",
+ srcs: ["libbinder_rpc_unstable.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ ],
+ export_include_dirs: ["include_rpc_unstable"],
+
+ // enumerate stable entry points, for apex use
+ stubs: {
+ symbol_file: "libbinder_rpc_unstable.map.txt",
+ },
+
+ // This library is intentionally limited to these targets, and it will be removed later.
+ // Do not expand the visibility.
+ visibility: [
+ "//packages/modules/Virtualization:__subpackages__",
+ ],
+}
+
+filegroup {
+ name: "libbinder_rpc_unstable_header",
+ srcs: ["include_rpc_unstable/binder_rpc_unstable.hpp"],
+}
+
// 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.
@@ -321,3 +408,18 @@
export_aidl_headers: true,
},
}
+
+cc_binary {
+ name: "servicedispatcher",
+ host_supported: false,
+ srcs: [
+ "servicedispatcher.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ "android.debug_aidl-cpp",
+ ],
+}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index d5bdd1c..39befbe 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -17,16 +17,26 @@
#include <binder/Binder.h>
#include <atomic>
-#include <utils/misc.h>
+#include <set>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <private/android_filesystem_config.h>
+#include <utils/misc.h>
+#include <inttypes.h>
#include <linux/sched.h>
#include <stdio.h>
+#include "RpcState.h"
+
namespace android {
// Service implementations inherit from BBinder and IBinder, and this is frozen
@@ -39,6 +49,14 @@
static_assert(sizeof(BBinder) == 20);
#endif
+#ifdef BINDER_RPC_DEV_SERVERS
+constexpr const bool kEnableRpcDevServers = true;
+#else
+constexpr const bool kEnableRpcDevServers = false;
+#endif
+
+// Log any reply transactions for which the data exceeds this size
+#define LOG_REPLIES_OVER_SIZE (300 * 1024)
// ---------------------------------------------------------------------------
IBinder::IBinder()
@@ -136,8 +154,79 @@
return OK;
}
+status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd,
+ const sp<IBinder>& keepAliveBinder) {
+ if constexpr (!kEnableRpcDevServers) {
+ ALOGW("setRpcClientDebug disallowed because RPC is not enabled");
+ return INVALID_OPERATION;
+ }
+
+ BBinder* local = this->localBinder();
+ if (local != nullptr) {
+ return local->BBinder::setRpcClientDebug(std::move(socketFd), keepAliveBinder);
+ }
+
+ BpBinder* proxy = this->remoteBinder();
+ LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote");
+
+ Parcel data;
+ Parcel reply;
+ status_t status;
+ if (status = data.writeBool(socketFd.ok()); status != OK) return status;
+ if (socketFd.ok()) {
+ // writeUniqueFileDescriptor currently makes an unnecessary dup().
+ status = data.writeFileDescriptor(socketFd.release(), true /* own */);
+ if (status != OK) return status;
+ }
+ if (status = data.writeStrongBinder(keepAliveBinder); status != OK) return status;
+ return transact(SET_RPC_CLIENT_TRANSACTION, data, &reply);
+}
+
+void IBinder::withLock(const std::function<void()>& doWithLock) {
+ BBinder* local = localBinder();
+ if (local) {
+ local->withLock(doWithLock);
+ return;
+ }
+ BpBinder* proxy = this->remoteBinder();
+ LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote");
+ proxy->withLock(doWithLock);
+}
+
// ---------------------------------------------------------------------------
+class BBinder::RpcServerLink : public IBinder::DeathRecipient {
+public:
+ // On binder died, calls RpcServer::shutdown on @a rpcServer, and removes itself from @a binder.
+ RpcServerLink(const sp<RpcServer>& rpcServer, const sp<IBinder>& keepAliveBinder,
+ const wp<BBinder>& binder)
+ : mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
+ void binderDied(const wp<IBinder>&) override {
+ LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
+ if (mRpcServer == nullptr) {
+ ALOGW("RpcServerLink: Unable to shut down RpcServer because it does not exist.");
+ } else {
+ ALOGW_IF(!mRpcServer->shutdown(),
+ "RpcServerLink: RpcServer did not shut down properly. Not started?");
+ }
+ mRpcServer.clear();
+
+ auto promoted = mBinder.promote();
+ if (promoted == nullptr) {
+ ALOGW("RpcServerLink: Unable to remove link from parent binder object because parent "
+ "binder object is gone.");
+ } else {
+ promoted->removeRpcServerLink(sp<RpcServerLink>::fromExisting(this));
+ }
+ mBinder.clear();
+ }
+
+private:
+ sp<RpcServer> mRpcServer;
+ sp<IBinder> mKeepAliveBinder; // hold to avoid automatically unlinking
+ wp<BBinder> mBinder;
+};
+
class BBinder::Extras
{
public:
@@ -150,14 +239,13 @@
// for below objects
Mutex mLock;
+ std::set<sp<RpcServerLink>> mRpcServerLinks;
BpBinder::ObjectManager mObjects;
};
// ---------------------------------------------------------------------------
-BBinder::BBinder() : mExtras(nullptr), mStability(0)
-{
-}
+BBinder::BBinder() : mExtras(nullptr), mStability(0), mParceled(false) {}
bool BBinder::isBinderAlive() const
{
@@ -194,11 +282,17 @@
err = pingBinder();
break;
case EXTENSION_TRANSACTION:
+ CHECK(reply != nullptr);
err = reply->writeStrongBinder(getExtension());
break;
case DEBUG_PID_TRANSACTION:
+ CHECK(reply != nullptr);
err = reply->writeInt32(getDebugPid());
break;
+ case SET_RPC_CLIENT_TRANSACTION: {
+ err = setRpcClientDebug(data);
+ break;
+ }
default:
err = onTransact(code, data, reply, flags);
break;
@@ -207,6 +301,10 @@
// In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
+ if (reply->dataSize() > LOG_REPLIES_OVER_SIZE) {
+ ALOGW("Large reply transaction of %zu bytes, interface descriptor %s, code %d",
+ reply->dataSize(), String8(getInterfaceDescriptor()).c_str(), code);
+ }
}
return err;
@@ -233,15 +331,13 @@
return NO_ERROR;
}
-void BBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
+void* BBinder::attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) {
Extras* e = getOrCreateExtras();
- if (!e) return; // out of memory
+ LOG_ALWAYS_FATAL_IF(!e, "no memory");
AutoMutex _l(e->mLock);
- e->mObjects.attach(objectID, object, cleanupCookie, func);
+ return e->mObjects.attach(objectID, object, cleanupCookie, func);
}
void* BBinder::findObject(const void* objectID) const
@@ -253,13 +349,20 @@
return e->mObjects.find(objectID);
}
-void BBinder::detachObject(const void* objectID)
-{
+void* BBinder::detachObject(const void* objectID) {
Extras* e = mExtras.load(std::memory_order_acquire);
- if (!e) return;
+ if (!e) return nullptr;
AutoMutex _l(e->mLock);
- e->mObjects.detach(objectID);
+ return e->mObjects.detach(objectID);
+}
+
+void BBinder::withLock(const std::function<void()>& doWithLock) {
+ Extras* e = getOrCreateExtras();
+ LOG_ALWAYS_FATAL_IF(!e, "no memory");
+
+ AutoMutex _l(e->mLock);
+ doWithLock();
}
BBinder* BBinder::localBinder()
@@ -276,6 +379,10 @@
void BBinder::setRequestingSid(bool requestingSid)
{
+ LOG_ALWAYS_FATAL_IF(mParceled,
+ "setRequestingSid() should not be called after a binder object "
+ "is parceled/sent to another process");
+
Extras* e = mExtras.load(std::memory_order_acquire);
if (!e) {
@@ -298,6 +405,10 @@
}
void BBinder::setMinSchedulerPolicy(int policy, int priority) {
+ LOG_ALWAYS_FATAL_IF(mParceled,
+ "setMinSchedulerPolicy() should not be called after a binder object "
+ "is parceled/sent to another process");
+
switch (policy) {
case SCHED_NORMAL:
LOG_ALWAYS_FATAL_IF(priority < -20 || priority > 19, "Invalid priority for SCHED_NORMAL: %d", priority);
@@ -345,6 +456,10 @@
}
void BBinder::setInheritRt(bool inheritRt) {
+ LOG_ALWAYS_FATAL_IF(mParceled,
+ "setInheritRt() should not be called after a binder object "
+ "is parceled/sent to another process");
+
Extras* e = mExtras.load(std::memory_order_acquire);
if (!e) {
@@ -364,12 +479,113 @@
}
void BBinder::setExtension(const sp<IBinder>& extension) {
+ LOG_ALWAYS_FATAL_IF(mParceled,
+ "setExtension() should not be called after a binder object "
+ "is parceled/sent to another process");
+
Extras* e = getOrCreateExtras();
e->mExtension = extension;
}
+bool BBinder::wasParceled() {
+ return mParceled;
+}
+
+void BBinder::setParceled() {
+ mParceled = true;
+}
+
+status_t BBinder::setRpcClientDebug(const Parcel& data) {
+ if constexpr (!kEnableRpcDevServers) {
+ ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_ROOT) {
+ ALOGE("%s: not allowed because client %" PRIu32 " is not root", __PRETTY_FUNCTION__, uid);
+ return PERMISSION_DENIED;
+ }
+ status_t status;
+ bool hasSocketFd;
+ android::base::unique_fd clientFd;
+
+ if (status = data.readBool(&hasSocketFd); status != OK) return status;
+ if (hasSocketFd) {
+ if (status = data.readUniqueFileDescriptor(&clientFd); status != OK) return status;
+ }
+ sp<IBinder> keepAliveBinder;
+ if (status = data.readNullableStrongBinder(&keepAliveBinder); status != OK) return status;
+
+ return setRpcClientDebug(std::move(clientFd), keepAliveBinder);
+}
+
+status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd,
+ const sp<IBinder>& keepAliveBinder) {
+ if constexpr (!kEnableRpcDevServers) {
+ ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ const int socketFdForPrint = socketFd.get();
+ LOG_RPC_DETAIL("%s(fd=%d)", __PRETTY_FUNCTION__, socketFdForPrint);
+
+ if (!socketFd.ok()) {
+ ALOGE("%s: No socket FD provided.", __PRETTY_FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (keepAliveBinder == nullptr) {
+ ALOGE("%s: No keepAliveBinder provided.", __PRETTY_FUNCTION__);
+ return UNEXPECTED_NULL;
+ }
+
+ size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxThreadCount();
+ if (binderThreadPoolMaxCount <= 1) {
+ ALOGE("%s: ProcessState thread pool max count is %zu. RPC is disabled for this service "
+ "because RPC requires the service to support multithreading.",
+ __PRETTY_FUNCTION__, binderThreadPoolMaxCount);
+ return INVALID_OPERATION;
+ }
+
+ // Weak ref to avoid circular dependency:
+ // BBinder -> RpcServerLink ----> RpcServer -X-> BBinder
+ // `-X-> BBinder
+ auto weakThis = wp<BBinder>::fromExisting(this);
+
+ Extras* e = getOrCreateExtras();
+ AutoMutex _l(e->mLock);
+ auto rpcServer = RpcServer::make();
+ LOG_ALWAYS_FATAL_IF(rpcServer == nullptr, "RpcServer::make returns null");
+ auto link = sp<RpcServerLink>::make(rpcServer, keepAliveBinder, weakThis);
+ if (auto status = keepAliveBinder->linkToDeath(link, nullptr, 0); status != OK) {
+ ALOGE("%s: keepAliveBinder->linkToDeath returns %s", __PRETTY_FUNCTION__,
+ statusToString(status).c_str());
+ return status;
+ }
+ rpcServer->setRootObjectWeak(weakThis);
+ if (auto status = rpcServer->setupExternalServer(std::move(socketFd)); status != OK) {
+ return status;
+ }
+ rpcServer->setMaxThreads(binderThreadPoolMaxCount);
+ rpcServer->start();
+ e->mRpcServerLinks.emplace(link);
+ LOG_RPC_DETAIL("%s(fd=%d) successful", __PRETTY_FUNCTION__, socketFdForPrint);
+ return OK;
+}
+
+void BBinder::removeRpcServerLink(const sp<RpcServerLink>& link) {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ if (!e) return;
+ AutoMutex _l(e->mLock);
+ (void)e->mRpcServerLinks.erase(link);
+}
+
BBinder::~BBinder()
{
+ if (!wasParceled() && getExtension()) {
+ ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+ }
+
Extras* e = mExtras.load(std::memory_order_relaxed);
if (e) delete e;
}
@@ -381,6 +597,7 @@
{
switch (code) {
case INTERFACE_TRANSACTION:
+ CHECK(reply != nullptr);
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 6471aa6..921e57c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -37,7 +37,7 @@
Mutex BpBinder::sTrackingLock;
std::unordered_map<int32_t, uint32_t> BpBinder::sTrackingMap;
-std::unordered_map<int32_t, uint32_t> sLastLimitCallbackMap;
+std::unordered_map<int32_t, uint32_t> BpBinder::sLastLimitCallbackMap;
int BpBinder::sNumTrackedUids = 0;
std::atomic_bool BpBinder::sCountByUidEnabled(false);
binder_proxy_limit_callback BpBinder::sLimitCallback;
@@ -48,6 +48,9 @@
// Another arbitrary value a binder count needs to drop below before another callback will be called
uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
+// Log any transactions for which the data exceeds this size
+#define LOG_TRANSACTIONS_OVER_SIZE (300 * 1024)
+
enum {
LIMIT_REACHED_MASK = 0x80000000, // A flag denoting that the limit has been reached
COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value
@@ -62,44 +65,47 @@
kill();
}
-void BpBinder::ObjectManager::attach(
- const void* objectID, void* object, void* cleanupCookie,
- IBinder::object_cleanup_func func)
-{
+void* BpBinder::ObjectManager::attach(const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func) {
entry_t e;
e.object = object;
e.cleanupCookie = cleanupCookie;
e.func = func;
- if (mObjects.indexOfKey(objectID) >= 0) {
- ALOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
- objectID, this, object);
- return;
+ if (mObjects.find(objectID) != mObjects.end()) {
+ ALOGI("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object "
+ "ID already in use",
+ objectID, this, object);
+ return mObjects[objectID].object;
}
- mObjects.add(objectID, e);
+ mObjects.insert({objectID, e});
+ return nullptr;
}
void* BpBinder::ObjectManager::find(const void* objectID) const
{
- const ssize_t i = mObjects.indexOfKey(objectID);
- if (i < 0) return nullptr;
- return mObjects.valueAt(i).object;
+ auto i = mObjects.find(objectID);
+ if (i == mObjects.end()) return nullptr;
+ return i->second.object;
}
-void BpBinder::ObjectManager::detach(const void* objectID)
-{
- mObjects.removeItem(objectID);
+void* BpBinder::ObjectManager::detach(const void* objectID) {
+ auto i = mObjects.find(objectID);
+ if (i == mObjects.end()) return nullptr;
+ void* value = i->second.object;
+ mObjects.erase(i);
+ return value;
}
void BpBinder::ObjectManager::kill()
{
const size_t N = mObjects.size();
ALOGV("Killing %zu objects in manager %p", N, this);
- for (size_t i=0; i<N; i++) {
- const entry_t& e = mObjects.valueAt(i);
+ for (auto i : mObjects) {
+ const entry_t& e = i.second;
if (e.func != nullptr) {
- e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ e.func(i.first, e.object, e.cleanupCookie);
}
}
@@ -149,7 +155,7 @@
return sp<BpBinder>::make(BinderHandle{handle}, trackedUid);
}
-sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, const RpcAddress& address) {
+sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, uint64_t address) {
LOG_ALWAYS_FATAL_IF(session == nullptr, "BpBinder::create null session");
// These are not currently tracked, since there is no UID or other
@@ -186,7 +192,7 @@
return std::holds_alternative<RpcHandle>(mHandle);
}
-const RpcAddress& BpBinder::rpcAddress() const {
+uint64_t BpBinder::rpcAddress() const {
return std::get<RpcHandle>(mHandle).address;
}
@@ -198,6 +204,14 @@
return std::get<BinderHandle>(mHandle).handle;
}
+std::optional<int32_t> BpBinder::getDebugBinderHandle() const {
+ if (!isRpcBinder()) {
+ return binderHandle();
+ } else {
+ return std::nullopt;
+ }
+}
+
bool BpBinder::isDescriptorCached() const {
Mutex::Autolock _l(mLock);
return mDescriptorCache.size() ? true : false;
@@ -271,25 +285,34 @@
if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
using android::internal::Stability;
- auto category = Stability::getCategory(this);
+ int16_t stability = Stability::getRepr(this);
Stability::Level required = privateVendor ? Stability::VENDOR
: Stability::getLocalLevel();
- if (CC_UNLIKELY(!Stability::check(category, required))) {
+ if (CC_UNLIKELY(!Stability::check(stability, required))) {
ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
- category.debugString().c_str(),
- String8(getInterfaceDescriptor()).c_str(),
- Stability::levelString(required).c_str());
+ Stability::levelString(stability).c_str(),
+ String8(getInterfaceDescriptor()).c_str(),
+ Stability::levelString(required).c_str());
return BAD_TYPE;
}
}
status_t status;
if (CC_UNLIKELY(isRpcBinder())) {
- status = rpcSession()->transact(rpcAddress(), code, data, reply, flags);
+ status = rpcSession()->transact(sp<IBinder>::fromExisting(this), code, data, reply,
+ flags);
} else {
status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
}
+ if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
+ Mutex::Autolock _l(mLock);
+ ALOGW("Large outgoing transaction of %zu bytes, interface descriptor %s, code %d",
+ data.dataSize(),
+ mDescriptorCache.size() ? String8(mDescriptorCache).c_str()
+ : "<uncached descriptor>",
+ code);
+ }
if (status == DEAD_OBJECT) mAlive = 0;
@@ -418,14 +441,11 @@
recipient->binderDied(wp<BpBinder>::fromExisting(this));
}
-
-void BpBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
+void* BpBinder::attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) {
AutoMutex _l(mLock);
ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
- mObjects.attach(objectID, object, cleanupCookie, func);
+ return mObjects.attach(objectID, object, cleanupCookie, func);
}
void* BpBinder::findObject(const void* objectID) const
@@ -434,10 +454,14 @@
return mObjects.find(objectID);
}
-void BpBinder::detachObject(const void* objectID)
-{
+void* BpBinder::detachObject(const void* objectID) {
AutoMutex _l(mLock);
- mObjects.detach(objectID);
+ return mObjects.detach(objectID);
+}
+
+void BpBinder::withLock(const std::function<void()>& doWithLock) {
+ AutoMutex _l(mLock);
+ doWithLock();
}
BpBinder* BpBinder::remoteBinder()
@@ -493,7 +517,7 @@
{
ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
if (CC_UNLIKELY(isRpcBinder())) {
- (void)rpcSession()->sendDecStrong(rpcAddress());
+ (void)rpcSession()->sendDecStrong(this);
return;
}
IF_ALOGV() {
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index fdd532a..57e03cb 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -18,8 +18,8 @@
#define ANDROID_BUFFEREDTEXTOUTPUT_H
#include <binder/TextOutput.h>
-#include <utils/threads.h>
#include <sys/uio.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index 8676955..e4ac4b4 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -26,22 +26,6 @@
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 7ca087e..262dfba 100644
--- a/libs/binder/Debug.h
+++ b/libs/binder/Debug.h
@@ -23,8 +23,6 @@
namespace android {
// ---------------------------------------------------------------------------
-std::string hexString(const void* data, size_t size);
-
const char* stringForIndent(int32_t indentLevel);
typedef void (*debugPrintFunc)(void* cookie, const char* txt);
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
new file mode 100644
index 0000000..5e22593
--- /dev/null
+++ b/libs/binder/FdTrigger.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FdTrigger"
+#include <log/log.h>
+
+#include "FdTrigger.h"
+
+#include <poll.h>
+
+#include <android-base/macros.h>
+
+#include "RpcState.h"
+namespace android {
+
+std::unique_ptr<FdTrigger> FdTrigger::make() {
+ auto ret = std::make_unique<FdTrigger>();
+ if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
+ ALOGE("Could not create pipe %s", strerror(errno));
+ return nullptr;
+ }
+ return ret;
+}
+
+void FdTrigger::trigger() {
+ mWrite.reset();
+}
+
+bool FdTrigger::isTriggered() {
+ return mWrite == -1;
+}
+
+status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+ LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed", fd.get());
+ pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+ {.fd = mRead.get(), .events = 0, .revents = 0}};
+ int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
+ if (ret < 0) {
+ return -errno;
+ }
+ LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", fd.get());
+
+ // At least one FD has events. Check them.
+
+ // Detect explicit trigger(): DEAD_OBJECT
+ if (pfd[1].revents & POLLHUP) {
+ return DEAD_OBJECT;
+ }
+ // See unknown flags in trigger FD's revents (POLLERR / POLLNVAL).
+ // Treat this error condition as UNKNOWN_ERROR.
+ if (pfd[1].revents != 0) {
+ ALOGE("Unknown revents on trigger FD %d: revents = %d", pfd[1].fd, pfd[1].revents);
+ return UNKNOWN_ERROR;
+ }
+
+ // pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
+ // a subset of event | POLLHUP | POLLERR | POLLNVAL.
+
+ // POLLNVAL: invalid FD number, e.g. not opened.
+ if (pfd[0].revents & POLLNVAL) {
+ return BAD_VALUE;
+ }
+
+ // Error condition. It wouldn't be possible to do I/O on |fd| afterwards.
+ // Note: If this is the write end of a pipe then POLLHUP may also be set simultaneously. We
+ // still want DEAD_OBJECT in this case.
+ if (pfd[0].revents & POLLERR) {
+ LOG_RPC_DETAIL("poll() incoming FD %d results in revents = %d", pfd[0].fd, pfd[0].revents);
+ return DEAD_OBJECT;
+ }
+
+ // Success condition; event flag(s) set. Even though POLLHUP may also be set,
+ // treat it as a success condition to ensure data is drained.
+ if (pfd[0].revents & event) {
+ return OK;
+ }
+
+ // POLLHUP: Peer closed connection. Treat as DEAD_OBJECT.
+ // This is a very common case, so don't log.
+ return DEAD_OBJECT;
+}
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
new file mode 100644
index 0000000..a545d6c
--- /dev/null
+++ b/libs/binder/FdTrigger.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <memory>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+/** This is not a pipe. */
+class FdTrigger {
+public:
+ /** Returns nullptr for error case */
+ static std::unique_ptr<FdTrigger> make();
+
+ /**
+ * Close the write end of the pipe so that the read end receives POLLHUP.
+ * Not threadsafe.
+ */
+ void trigger();
+
+ /**
+ * Check whether this has been triggered by checking the write end. Note:
+ * this has no internal locking, and it is inherently racey, but this is
+ * okay, because if we accidentally return false when a trigger has already
+ * happened, we can imagine that instead, the scheduler actually executed
+ * the code which is polling isTriggered earlier.
+ */
+ [[nodiscard]] bool isTriggered();
+
+ /**
+ * Poll for a read event.
+ *
+ * event - for pollfd
+ *
+ * Return:
+ * true - time to read!
+ * false - trigger happened
+ */
+ [[nodiscard]] status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
+
+private:
+ base::unique_fd mWrite;
+ base::unique_fd mRead;
+};
+} // namespace android
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index bd974b0..c6b0cb7 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -31,8 +31,9 @@
#include <binder/Parcel.h>
#include <log/log.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
+
+#include <map>
#define VERBOSE 0
@@ -63,7 +64,7 @@
void free_heap(const wp<IBinder>& binder);
Mutex mHeapCacheLock; // Protects entire vector below.
- KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+ std::map<wp<IBinder>, heap_info_t> mHeapCache;
// We do not use the copy-on-write capabilities of KeyedVector.
// TODO: Reimplemement based on standard C++ container?
};
@@ -434,9 +435,9 @@
sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
{
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info = mHeapCache.editValueAt(i);
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end()) {
+ heap_info_t& info = i->second;
ALOGD_IF(VERBOSE,
"found binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
binder.get(), info.heap.get(),
@@ -452,7 +453,7 @@
info.count = 1;
//ALOGD("adding binder=%p, heap=%p, count=%d",
// binder.get(), info.heap.get(), info.count);
- mHeapCache.add(binder, info);
+ mHeapCache.insert({binder, info});
return info.heap;
}
}
@@ -466,9 +467,9 @@
sp<IMemoryHeap> rel;
{
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end()) {
+ heap_info_t& info = i->second;
if (--info.count == 0) {
ALOGD_IF(VERBOSE,
"removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
@@ -477,8 +478,8 @@
static_cast<BpMemoryHeap*>(info.heap.get())
->mHeapId.load(memory_order_relaxed),
info.count);
- rel = mHeapCache.valueAt(i).heap;
- mHeapCache.removeItemsAt(i);
+ rel = i->second.heap;
+ mHeapCache.erase(i);
}
} else {
ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
@@ -490,23 +491,23 @@
{
sp<IMemoryHeap> realHeap;
Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
- else realHeap = interface_cast<IMemoryHeap>(binder);
+ auto i = mHeapCache.find(binder);
+ if (i != mHeapCache.end())
+ realHeap = i->second.heap;
+ else
+ realHeap = interface_cast<IMemoryHeap>(binder);
return realHeap;
}
void HeapCache::dump_heaps()
{
Mutex::Autolock _l(mHeapCacheLock);
- int c = mHeapCache.size();
- for (int i=0 ; i<c ; i++) {
- const heap_info_t& info = mHeapCache.valueAt(i);
+ for (const auto& i : mHeapCache) {
+ const heap_info_t& info = i.second;
BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
- ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)",
- mHeapCache.keyAt(i).unsafe_get(),
- info.heap.get(), info.count,
- h->mHeapId.load(memory_order_relaxed), h->mBase, h->mSize);
+ ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)", i.first.unsafe_get(),
+ info.heap.get(), info.count, h->mHeapId.load(memory_order_relaxed), h->mBase,
+ h->mSize);
}
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index c415ea0..3c97dca 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -27,7 +27,6 @@
#include <utils/CallStack.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
-#include <utils/threads.h>
#include <atomic>
#include <errno.h>
@@ -352,11 +351,6 @@
return gDisableBackgroundScheduling.load(std::memory_order_relaxed);
}
-sp<ProcessState> IPCThreadState::process()
-{
- return mProcess;
-}
-
status_t IPCThreadState::clearLastError()
{
const status_t err = mLastError;
@@ -366,19 +360,46 @@
pid_t IPCThreadState::getCallingPid() const
{
+ checkContextIsBinderForUse(__func__);
return mCallingPid;
}
const char* IPCThreadState::getCallingSid() const
{
+ checkContextIsBinderForUse(__func__);
return mCallingSid;
}
uid_t IPCThreadState::getCallingUid() const
{
+ checkContextIsBinderForUse(__func__);
return mCallingUid;
}
+const IPCThreadState::SpGuard* IPCThreadState::pushGetCallingSpGuard(const SpGuard* guard) {
+ const SpGuard* orig = mServingStackPointerGuard;
+ mServingStackPointerGuard = guard;
+ return orig;
+}
+
+void IPCThreadState::restoreGetCallingSpGuard(const SpGuard* guard) {
+ mServingStackPointerGuard = guard;
+}
+
+void IPCThreadState::checkContextIsBinderForUse(const char* use) const {
+ if (LIKELY(mServingStackPointerGuard == nullptr)) return;
+
+ if (!mServingStackPointer || mServingStackPointerGuard->address < mServingStackPointer) {
+ LOG_ALWAYS_FATAL("In context %s, %s does not make sense (binder sp: %p, guard: %p).",
+ mServingStackPointerGuard->context, use, mServingStackPointer,
+ mServingStackPointerGuard->address);
+ }
+
+ // in the case mServingStackPointer is deeper in the stack than the guard,
+ // we must be serving a binder transaction (maybe nested). This is a binder
+ // context, so we don't abort
+}
+
int64_t IPCThreadState::clearCallingIdentity()
{
// ignore mCallingSid for legacy reasons
@@ -845,6 +866,7 @@
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mServingStackPointer(nullptr),
+ mServingStackPointerGuard(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mIsLooper(false),
@@ -1176,7 +1198,8 @@
case BR_DECREFS:
refs = (RefBase::weakref_type*)mIn.readPointer();
- obj = (BBinder*)mIn.readPointer();
+ // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
+ obj = (BBinder*)mIn.readPointer(); // consume
// NOTE: This assertion is not valid, because the object may no
// longer exist (thus the (BBinder*)cast above resulting in a different
// memory address).
@@ -1226,7 +1249,7 @@
tr.offsets_size/sizeof(binder_size_t), freeBuffer);
const void* origServingStackPointer = mServingStackPointer;
- mServingStackPointer = &origServingStackPointer; // anything on the stack
+ mServingStackPointer = __builtin_frame_address(0);
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
@@ -1382,28 +1405,11 @@
}
}
-status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, bool *sync_received, bool *async_received)
-{
- int ret = 0;
- binder_frozen_status_info info;
- info.pid = pid;
-
-#if defined(__ANDROID__)
- if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_FROZEN_INFO, &info) < 0)
- ret = -errno;
-#endif
- *sync_received = info.sync_recv;
- *async_received = info.async_recv;
-
- return ret;
-}
-
-#ifndef __ANDROID_VNDK__
status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
uint32_t *async_received)
{
int ret = 0;
- binder_frozen_status_info info;
+ binder_frozen_status_info info = {};
info.pid = pid;
#if defined(__ANDROID__)
@@ -1415,7 +1421,6 @@
return ret;
}
-#endif
status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) {
struct binder_freeze_info info;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index f684cf6..ea2f8d2 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -35,12 +35,16 @@
#ifdef __ANDROID__
#include <cutils/properties.h>
+#else
+#include "ServiceManagerHost.h"
#endif
#include "Static.h"
namespace android {
+using AidlRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+
using AidlServiceManager = android::os::IServiceManager;
using android::binder::Status;
@@ -76,7 +80,25 @@
bool isDeclared(const String16& name) override;
Vector<String16> getDeclaredInstances(const String16& interface) override;
std::optional<String16> updatableViaApex(const String16& name) override;
+ std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+ class RegistrationWaiter : public android::os::BnServiceCallback {
+ public:
+ explicit RegistrationWaiter(const sp<AidlRegistrationCallback>& callback)
+ : mImpl(callback) {}
+ Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
+ mImpl->onServiceRegistration(String16(name.c_str()), binder);
+ return Status::ok();
+ }
+ private:
+ sp<AidlRegistrationCallback> mImpl;
+ };
+
+ status_t registerForNotifications(const String16& service,
+ const sp<AidlRegistrationCallback>& cb) override;
+
+ status_t unregisterForNotifications(const String16& service,
+ const sp<AidlRegistrationCallback>& cb) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
return mTheRealServiceManager->getInterfaceDescriptor();
@@ -84,8 +106,30 @@
IBinder* onAsBinder() override {
return IInterface::asBinder(mTheRealServiceManager).get();
}
-private:
+
+protected:
sp<AidlServiceManager> mTheRealServiceManager;
+ // AidlRegistrationCallback -> services that its been registered for
+ // notifications.
+ using LocalRegistrationAndWaiter =
+ std::pair<sp<LocalRegistrationCallback>, sp<RegistrationWaiter>>;
+ using ServiceCallbackMap = std::map<std::string, std::vector<LocalRegistrationAndWaiter>>;
+ ServiceCallbackMap mNameToRegistrationCallback;
+ std::mutex mNameToRegistrationLock;
+
+ void removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter);
+
+ // Directly get the service in a way that, for lazy services, requests the service to be started
+ // if it is not currently started. This way, calls directly to ServiceManagerShim::getService
+ // will still have the 5s delay that is expected by a large amount of Android code.
+ //
+ // When implementing ServiceManagerShim, use realGetService instead of
+ // mTheRealServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
+ virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
+ return mTheRealServiceManager->getService(name, _aidl_return);
+ }
};
[[clang::no_destroy]] static std::once_flag gSmOnce;
@@ -129,8 +173,7 @@
return checkCallingPermission(permission, nullptr, nullptr);
}
-static String16 _permission("permission");
-
+static StaticString16 _permission(u"permission");
bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
{
@@ -142,8 +185,7 @@
return checkPermission(permission, pid, uid);
}
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
-{
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure) {
static Mutex gPermissionControllerLock;
static sp<IPermissionController> gPermissionController;
@@ -168,8 +210,10 @@
// Is this a permission failure, or did the controller go away?
if (IInterface::asBinder(pc)->isBinderAlive()) {
- ALOGW("Permission failure: %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
+ if (logPermissionFailure) {
+ ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(),
+ uid, pid);
+ }
return false;
}
@@ -320,14 +364,18 @@
const std::string name = String8(name16).c_str();
sp<IBinder> out;
- if (!mTheRealServiceManager->getService(name, &out).isOk()) {
+ if (Status status = realGetService(name, &out); !status.isOk()) {
+ ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(),
+ status.toString8().c_str());
return nullptr;
}
if (out != nullptr) return out;
sp<Waiter> waiter = sp<Waiter>::make();
- if (!mTheRealServiceManager->registerForNotifications(
- name, waiter).isOk()) {
+ if (Status status = mTheRealServiceManager->registerForNotifications(name, waiter);
+ !status.isOk()) {
+ ALOGW("Failed to registerForNotifications in waitForService for %s: %s", name.c_str(),
+ status.toString8().c_str());
return nullptr;
}
Defer unregister ([&] {
@@ -360,7 +408,9 @@
// - init gets death signal, but doesn't know it needs to restart
// the service
// - we need to request service again to get it to start
- if (!mTheRealServiceManager->getService(name, &out).isOk()) {
+ if (Status status = realGetService(name, &out); !status.isOk()) {
+ ALOGW("Failed to getService in waitForService on later try for %s: %s", name.c_str(),
+ status.toString8().c_str());
return nullptr;
}
if (out != nullptr) return out;
@@ -369,7 +419,10 @@
bool ServiceManagerShim::isDeclared(const String16& name) {
bool declared;
- if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) {
+ if (Status status = mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared);
+ !status.isOk()) {
+ ALOGW("Failed to get isDeclard for %s: %s", String8(name).c_str(),
+ status.toString8().c_str());
return false;
}
return declared;
@@ -377,7 +430,11 @@
Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) {
std::vector<std::string> out;
- if (!mTheRealServiceManager->getDeclaredInstances(String8(interface).c_str(), &out).isOk()) {
+ if (Status status =
+ mTheRealServiceManager->getDeclaredInstances(String8(interface).c_str(), &out);
+ !status.isOk()) {
+ ALOGW("Failed to getDeclaredInstances for %s: %s", String8(interface).c_str(),
+ status.toString8().c_str());
return {};
}
@@ -391,10 +448,139 @@
std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
std::optional<std::string> declared;
- if (!mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared).isOk()) {
+ if (Status status = mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared);
+ !status.isOk()) {
+ ALOGW("Failed to get updatableViaApex for %s: %s", String8(name).c_str(),
+ status.toString8().c_str());
return std::nullopt;
}
return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
}
+std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo(
+ const String16& name) {
+ std::optional<os::ConnectionInfo> connectionInfo;
+ if (Status status =
+ mTheRealServiceManager->getConnectionInfo(String8(name).c_str(), &connectionInfo);
+ !status.isOk()) {
+ ALOGW("Failed to get ConnectionInfo for %s: %s", String8(name).c_str(),
+ status.toString8().c_str());
+ }
+ return connectionInfo.has_value()
+ ? std::make_optional<IServiceManager::ConnectionInfo>(
+ {connectionInfo->ipAddress, static_cast<unsigned int>(connectionInfo->port)})
+ : std::nullopt;
+}
+
+status_t ServiceManagerShim::registerForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
+ if (cb == nullptr) {
+ ALOGE("%s: null cb passed", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::string nameStr = String8(name).c_str();
+ sp<RegistrationWaiter> registrationWaiter = sp<RegistrationWaiter>::make(cb);
+ std::lock_guard<std::mutex> lock(mNameToRegistrationLock);
+ if (Status status =
+ mTheRealServiceManager->registerForNotifications(nameStr, registrationWaiter);
+ !status.isOk()) {
+ ALOGW("Failed to registerForNotifications for %s: %s", nameStr.c_str(),
+ status.toString8().c_str());
+ return UNKNOWN_ERROR;
+ }
+ mNameToRegistrationCallback[nameStr].push_back(std::make_pair(cb, registrationWaiter));
+ return OK;
+}
+
+void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter) {
+ std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second;
+ for (auto lit = localRegistrationAndWaiters.begin();
+ lit != localRegistrationAndWaiters.end();) {
+ if (lit->first == cb) {
+ if (waiter) {
+ *waiter = lit->second;
+ }
+ lit = localRegistrationAndWaiters.erase(lit);
+ } else {
+ ++lit;
+ }
+ }
+
+ if (localRegistrationAndWaiters.empty()) {
+ mNameToRegistrationCallback.erase(*it);
+ }
+}
+
+status_t ServiceManagerShim::unregisterForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
+ if (cb == nullptr) {
+ ALOGE("%s: null cb passed", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::string nameStr = String8(name).c_str();
+ std::lock_guard<std::mutex> lock(mNameToRegistrationLock);
+ auto it = mNameToRegistrationCallback.find(nameStr);
+ sp<RegistrationWaiter> registrationWaiter;
+ if (it != mNameToRegistrationCallback.end()) {
+ removeRegistrationCallbackLocked(cb, &it, ®istrationWaiter);
+ } else {
+ ALOGE("%s no callback registered for notifications on %s", __FUNCTION__, nameStr.c_str());
+ return BAD_VALUE;
+ }
+ if (registrationWaiter == nullptr) {
+ ALOGE("%s Callback passed wasn't used to register for notifications", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ if (Status status = mTheRealServiceManager->unregisterForNotifications(String8(name).c_str(),
+ registrationWaiter);
+ !status.isOk()) {
+ ALOGW("Failed to get service manager to unregisterForNotifications for %s: %s",
+ String8(name).c_str(), status.toString8().c_str());
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+
+#ifndef __ANDROID__
+// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
+// The internal implementation of the AIDL interface android::os::IServiceManager calls into
+// on-device service manager.
+class ServiceManagerHostShim : public ServiceManagerShim {
+public:
+ ServiceManagerHostShim(const sp<AidlServiceManager>& impl,
+ const RpcDelegateServiceManagerOptions& options)
+ : ServiceManagerShim(impl), mOptions(options) {}
+ // ServiceManagerShim::getService is based on checkService, so no need to override it.
+ sp<IBinder> checkService(const String16& name) const override {
+ return getDeviceService({String8(name).c_str()}, mOptions);
+ }
+
+protected:
+ // Override realGetService for ServiceManagerShim::waitForService.
+ Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
+ *_aidl_return = getDeviceService({"-g", name}, mOptions);
+ return Status::ok();
+ }
+
+private:
+ RpcDelegateServiceManagerOptions mOptions;
+};
+sp<IServiceManager> createRpcDelegateServiceManager(
+ const RpcDelegateServiceManagerOptions& options) {
+ auto binder = getDeviceService({"manager"}, options);
+ if (binder == nullptr) {
+ ALOGE("getDeviceService(\"manager\") returns null");
+ return nullptr;
+ }
+ auto interface = AidlServiceManager::asInterface(binder);
+ if (interface == nullptr) {
+ ALOGE("getDeviceService(\"manager\") returns non service manager");
+ return nullptr;
+ }
+ return sp<ServiceManagerHostShim>::make(interface, options);
+}
+#endif
+
} // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index c4475c7..03553f3 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -23,7 +23,6 @@
#include <utils/Log.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
-#include <utils/threads.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e1cbc19..8132d46 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -18,10 +18,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/memfd.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
@@ -34,6 +37,24 @@
// ---------------------------------------------------------------------------
+#ifdef __BIONIC__
+static int memfd_create_region(const char* name, size_t size) {
+ int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd == -1) {
+ ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno));
+ return -1;
+ }
+
+ if (ftruncate(fd, size) == -1) {
+ ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size,
+ strerror(errno));
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+#endif
+
MemoryHeapBase::MemoryHeapBase()
: mFD(-1), mSize(0), mBase(MAP_FAILED),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
@@ -45,15 +66,36 @@
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
- ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
- if (fd >= 0) {
- if (mapfd(fd, true, size) == NO_ERROR) {
- if (flags & READ_ONLY) {
- ashmem_set_prot_region(fd, PROT_READ);
- }
+ size = ((size + pagesize - 1) & ~(pagesize - 1));
+ int fd = -1;
+ if (mFlags & FORCE_MEMFD) {
+#ifdef __BIONIC__
+ ALOGV("MemoryHeapBase: Attempting to force MemFD");
+ fd = memfd_create_region(name ? name : "MemoryHeapBase", size);
+ if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+ const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) |
+ ((mFlags & MEMFD_ALLOW_SEALING) ? 0 : F_SEAL_SEAL);
+ if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
+ ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name,
+ SEAL_FLAGS, strerror(errno));
+ munmap(mBase, mSize);
+ mBase = nullptr;
+ mSize = 0;
+ close(fd);
}
+ return;
+#else
+ mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING);
+#endif
+ }
+ if (mFlags & MEMFD_ALLOW_SEALING) {
+ LOG_ALWAYS_FATAL("Invalid Flags. MEMFD_ALLOW_SEALING only valid with FORCE_MEMFD.");
+ }
+ fd = ashmem_create_region(name ? name : "MemoryHeapBase", size);
+ ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno));
+ if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return;
+ if (mFlags & READ_ONLY) {
+ ashmem_set_prot_region(fd, PROT_READ);
}
}
@@ -61,6 +103,9 @@
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
+ if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+ LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+ }
int open_flags = O_RDWR;
if (flags & NO_CACHING)
open_flags |= O_SYNC;
@@ -80,6 +125,9 @@
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
+ if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) {
+ LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor");
+ }
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
diff --git a/libs/binder/OWNERS b/libs/binder/OWNERS
index 350994a..f954e74 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,5 +1,6 @@
-arve@google.com
+# Bug component: 32456
ctate@google.com
hackbod@google.com
maco@google.com
smoreland@google.com
+tkjos@google.com
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 617708f..58b0b35 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -63,7 +63,7 @@
// This macro should never be used at runtime, as a too large value
// of s could cause an integer overflow. Instead, you should always
// use the wrapper function pad_size()
-#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
+#define PAD_SIZE_UNSAFE(s) (((s) + 3) & ~3UL)
static size_t pad_size(size_t s) {
if (s > (std::numeric_limits<size_t>::max() - 3)) {
@@ -98,13 +98,12 @@
BLOB_ASHMEM_MUTABLE = 2,
};
-static void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
-{
+static void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
+ const void* who) {
switch (obj.hdr.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
- LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
+ LOG_REFS("Parcel %p acquiring reference on local %llu", who, obj.cookie);
reinterpret_cast<IBinder*>(obj.cookie)->incStrong(who);
}
return;
@@ -117,13 +116,6 @@
return;
}
case BINDER_TYPE_FD: {
- if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
- // If we own an ashmem fd, keep track of how much memory it refers to.
- int size = ashmem_get_size_region(obj.handle);
- if (size > 0) {
- *outAshmemSize += size;
- }
- }
return;
}
}
@@ -131,13 +123,12 @@
ALOGD("Invalid object type 0x%08x", obj.hdr.type);
}
-static void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
-{
+static void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
+ const void* who) {
switch (obj.hdr.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
- LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
+ LOG_REFS("Parcel %p releasing reference on local %llu", who, obj.cookie);
reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who);
}
return;
@@ -151,16 +142,6 @@
}
case BINDER_TYPE_FD: {
if (obj.cookie != 0) { // owned
- if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
- int size = ashmem_get_size_region(obj.handle);
- if (size > 0) {
- // ashmem size might have changed since last time it was accounted for, e.g.
- // in acquire_object(). Value of *outAshmemSize is not critical since we are
- // releasing the object anyway. Check for integer overflow condition.
- *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
- }
- }
-
close(obj.handle);
}
return;
@@ -173,8 +154,8 @@
status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
{
internal::Stability::tryMarkCompilationUnit(binder.get());
- auto category = internal::Stability::getCategory(binder.get());
- return writeInt32(category.repr());
+ int16_t rep = internal::Stability::getRepr(binder.get());
+ return writeInt32(rep);
}
status_t Parcel::finishUnflattenBinder(
@@ -184,7 +165,8 @@
status_t status = readInt32(&stability);
if (status != OK) return status;
- status = internal::Stability::setRepr(binder.get(), stability, true /*log*/);
+ status = internal::Stability::setRepr(binder.get(), static_cast<int16_t>(stability),
+ true /*log*/);
if (status != OK) return status;
*out = binder;
@@ -195,16 +177,20 @@
return (priority & FLAT_BINDER_FLAG_PRIORITY_MASK) | ((policy & 3) << FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT);
}
-status_t Parcel::flattenBinder(const sp<IBinder>& binder)
-{
+status_t Parcel::flattenBinder(const sp<IBinder>& binder) {
+ BBinder* local = nullptr;
+ if (binder) local = binder->localBinder();
+ if (local) local->setParceled();
+
if (isForRpc()) {
if (binder) {
status_t status = writeInt32(1); // non-null
if (status != OK) return status;
- RpcAddress address = RpcAddress::zero();
+ uint64_t address;
+ // TODO(b/167966510): need to undo this if the Parcel is not sent
status = mSession->state()->onBinderLeaving(mSession, binder, &address);
if (status != OK) return status;
- status = address.writeToParcel(this);
+ status = writeUint64(address);
if (status != OK) return status;
} else {
status_t status = writeInt32(0); // null
@@ -214,7 +200,6 @@
}
flat_binder_object obj;
- obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
int schedBits = 0;
if (!IPCThreadState::self()->backgroundSchedulingDisabled()) {
@@ -222,20 +207,20 @@
}
if (binder != nullptr) {
- BBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == nullptr) {
ALOGE("null proxy");
} else {
if (proxy->isRpcBinder()) {
- ALOGE("Sending a socket binder over RPC is prohibited");
+ ALOGE("Sending a socket binder over kernel binder is prohibited");
return INVALID_OPERATION;
}
}
- const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
+ const int32_t handle = proxy ? proxy->getPrivateAccessor().binderHandle() : 0;
obj.hdr.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
+ obj.flags = 0;
obj.handle = handle;
obj.cookie = 0;
} else {
@@ -246,6 +231,7 @@
// override value, since it is set explicitly
schedBits = schedPolicyMask(policy, priority);
}
+ obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (local->isRequestingSid()) {
obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
}
@@ -258,6 +244,7 @@
}
} else {
obj.hdr.type = BINDER_TYPE_BINDER;
+ obj.flags = 0;
obj.binder = 0;
obj.cookie = 0;
}
@@ -275,17 +262,21 @@
if (isForRpc()) {
LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");
- int32_t isNull;
- status_t status = readInt32(&isNull);
+ int32_t isPresent;
+ status_t status = readInt32(&isPresent);
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 = mSession->state()->onBinderEntering(mSession, addr);
+ if (isPresent & 1) {
+ uint64_t addr;
+ if (status_t status = readUint64(&addr); status != OK) return status;
+ if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);
+ status != OK)
+ return status;
+ if (status_t status = mSession->state()->flushExcessBinderRefs(mSession, addr, binder);
+ status != OK)
+ return status;
}
return finishUnflattenBinder(binder, out);
@@ -422,8 +413,9 @@
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.");
+ if (mSession != parcel->mSession) {
+ ALOGE("Cannot append Parcel from one context to another. They may be different formats, "
+ "and objects are specific to a context.");
return BAD_TYPE;
}
@@ -504,7 +496,7 @@
flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(mData + off);
- acquire_object(proc, *flat, this, &mOpenAshmemSize);
+ acquire_object(proc, *flat, this);
if (flat->hdr.type == BINDER_TYPE_FD) {
// If this is a file descriptor, we need to dup it so the
@@ -531,6 +523,25 @@
return memcmp(data(), other.data(), size);
}
+status_t Parcel::compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+ size_t len, int* result) const {
+ if (len > INT32_MAX || thisOffset > INT32_MAX || otherOffset > INT32_MAX) {
+ // Don't accept size_t values which may have come from an inadvertent conversion from a
+ // negative int.
+ return BAD_VALUE;
+ }
+ size_t thisLimit;
+ if (__builtin_add_overflow(thisOffset, len, &thisLimit) || thisLimit > mDataSize) {
+ return BAD_VALUE;
+ }
+ size_t otherLimit;
+ if (__builtin_add_overflow(otherOffset, len, &otherLimit) || otherLimit > other.mDataSize) {
+ return BAD_VALUE;
+ }
+ *result = memcmp(data() + thisOffset, other.data() + otherOffset, len);
+ return NO_ERROR;
+}
+
bool Parcel::allowFds() const
{
return mAllowFds;
@@ -558,6 +569,74 @@
return mHasFds;
}
+std::vector<sp<IBinder>> Parcel::debugReadAllStrongBinders() const {
+ std::vector<sp<IBinder>> ret;
+
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ binder_size_t offset = mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_BINDER) continue;
+
+ setDataPosition(offset);
+
+ sp<IBinder> binder = readStrongBinder();
+ if (binder != nullptr) ret.push_back(binder);
+ }
+
+ setDataPosition(initPosition);
+ return ret;
+}
+
+std::vector<int> Parcel::debugReadAllFileDescriptors() const {
+ std::vector<int> ret;
+
+ size_t initPosition = dataPosition();
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ binder_size_t offset = mObjects[i];
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + offset);
+ if (flat->hdr.type != BINDER_TYPE_FD) continue;
+
+ setDataPosition(offset);
+
+ int fd = readFileDescriptor();
+ LOG_ALWAYS_FATAL_IF(fd == -1);
+ ret.push_back(fd);
+ }
+
+ setDataPosition(initPosition);
+ return ret;
+}
+
+status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
+ if (len > INT32_MAX || offset > INT32_MAX) {
+ // Don't accept size_t values which may have come from an inadvertent conversion from a
+ // negative int.
+ return BAD_VALUE;
+ }
+ size_t limit;
+ if (__builtin_add_overflow(offset, len, &limit) || limit > mDataSize) {
+ return BAD_VALUE;
+ }
+ *result = false;
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ size_t pos = mObjects[i];
+ if (pos < offset) continue;
+ if (pos + sizeof(flat_binder_object) > offset + len) {
+ if (mObjectsSorted) break;
+ else continue;
+ }
+ const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
+ if (flat->hdr.type == BINDER_TYPE_FD) {
+ *result = true;
+ break;
+ }
+ }
+ return NO_ERROR;
+}
+
void Parcel::markSensitive() const
{
mDeallocZero = true;
@@ -567,7 +646,7 @@
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().rpcSession());
+ markForRpc(binder->remoteBinder()->getPrivateAccessor().rpcSession());
}
}
@@ -594,6 +673,8 @@
#if defined(__ANDROID_VNDK__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
+#elif defined(__ANDROID_RECOVERY__)
+constexpr int32_t kHeader = B_PACK_CHARS('R', 'E', 'C', 'O');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
#endif
@@ -701,6 +782,17 @@
}
}
+binder::Status Parcel::enforceNoDataAvail() const {
+ const auto n = dataAvail();
+ if (n == 0) {
+ return binder::Status::ok();
+ }
+ return binder::Status::
+ fromExceptionCode(binder::Status::Exception::EX_BAD_PARCELABLE,
+ String8::format("Parcel data not fully consumed, unread size: %zu",
+ n));
+}
+
size_t Parcel::objectsCount() const
{
return mObjectsSize;
@@ -786,7 +878,7 @@
const size_t padded = pad_size(len);
- // sanity check for integer overflow
+ // check for integer overflow
if (mDataPos+padded < mDataPos) {
return nullptr;
}
@@ -1327,7 +1419,7 @@
// Need to write meta-data?
if (nullMetaData || val.binder != 0) {
mObjects[mObjectsSize] = mDataPos;
- acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
+ acquire_object(ProcessState::self(), val, this);
mObjectsSize++;
}
@@ -1466,9 +1558,33 @@
return nullptr;
}
+status_t Parcel::readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const {
+ if (status_t status = readInt32(size); status != OK) return status;
+ if (*size < 0) return OK; // may be null, client to handle
+
+ LOG_ALWAYS_FATAL_IF(elmSize > INT32_MAX, "Cannot have element as big as %zu", elmSize);
+
+ // approximation, can't know max element size (e.g. if it makes heap
+ // allocations)
+ static_assert(sizeof(int) == sizeof(int32_t), "Android is LP64");
+ int32_t allocationSize;
+ if (__builtin_smul_overflow(elmSize, *size, &allocationSize)) return NO_MEMORY;
+
+ // High limit of 1MB since something this big could never be returned. Could
+ // probably scope this down, but might impact very specific usecases.
+ constexpr int32_t kMaxAllocationSize = 1 * 1000 * 1000;
+
+ if (allocationSize >= kMaxAllocationSize) {
+ return NO_MEMORY;
+ }
+
+ return OK;
+}
+
template<class T>
status_t Parcel::readAligned(T *pArg) const {
static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+ static_assert(std::is_trivially_copyable_v<T>);
if ((mDataPos+sizeof(T)) <= mDataSize) {
if (mObjectsSize > 0) {
@@ -1480,9 +1596,8 @@
}
}
- const void* data = mData+mDataPos;
+ memcpy(pArg, mData + mDataPos, sizeof(T));
mDataPos += sizeof(T);
- *pArg = *reinterpret_cast<const T*>(data);
return NO_ERROR;
} else {
return NOT_ENOUGH_DATA;
@@ -1502,10 +1617,11 @@
template<class T>
status_t Parcel::writeAligned(T val) {
static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+ static_assert(std::is_trivially_copyable_v<T>);
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
- *reinterpret_cast<T*>(mData+mDataPos) = val;
+ memcpy(mData + mDataPos, &val, sizeof(val));
return finishWrite(sizeof(val));
}
@@ -1788,6 +1904,7 @@
{
status_t status = readNullableStrongBinder(val);
if (status == OK && !val->get()) {
+ ALOGW("Expecting binder but got null!");
status = UNEXPECTED_NULL;
}
return status;
@@ -2196,7 +2313,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
- release_object(proc, *flat, this, &mOpenAshmemSize);
+ release_object(proc, *flat, this);
}
}
@@ -2213,7 +2330,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
- acquire_object(proc, *flat, this, &mOpenAshmemSize);
+ acquire_object(proc, *flat, this);
}
}
@@ -2418,7 +2535,7 @@
// will need to rescan because we may have lopped off the only FDs
mFdsKnown = false;
}
- release_object(proc, *flat, this, &mOpenAshmemSize);
+ release_object(proc, *flat, this);
}
if (objectsSize == 0) {
@@ -2511,7 +2628,6 @@
mAllowFds = true;
mDeallocZero = false;
mOwner = nullptr;
- mOpenAshmemSize = 0;
mWorkSourceRequestHeaderPosition = 0;
mRequestHeaderPresent = false;
@@ -2528,18 +2644,9 @@
}
}
-void Parcel::scanForFds() const
-{
- bool hasFds = false;
- for (size_t i=0; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
- if (flat->hdr.type == BINDER_TYPE_FD) {
- hasFds = true;
- break;
- }
- }
- mHasFds = hasFds;
+void Parcel::scanForFds() const {
+ status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+ ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
mFdsKnown = true;
}
@@ -2547,13 +2654,28 @@
{
// This used to return the size of all blobs that were written to ashmem, now we're returning
// the ashmem currently referenced by this Parcel, which should be equivalent.
- // TODO: Remove method once ABI can be changed.
- return mOpenAshmemSize;
+ // TODO(b/202029388): Remove method once ABI can be changed.
+ return getOpenAshmemSize();
}
size_t Parcel::getOpenAshmemSize() const
{
- return mOpenAshmemSize;
+ size_t openAshmemSize = 0;
+ for (size_t i = 0; i < mObjectsSize; i++) {
+ const flat_binder_object* flat =
+ reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+
+ // cookie is compared against zero for historical reasons
+ // > obj.cookie = takeOwnership ? 1 : 0;
+ if (flat->hdr.type == BINDER_TYPE_FD && flat->cookie != 0 && ashmem_valid(flat->handle)) {
+ int size = ashmem_get_size_region(flat->handle);
+ if (__builtin_add_overflow(openAshmemSize, size, &openAshmemSize)) {
+ ALOGE("Overflow when computing ashmem size.");
+ return SIZE_MAX;
+ }
+ }
+ }
+ return openAshmemSize;
}
// --- Parcel::Blob ---
diff --git a/libs/binder/ParcelValTypes.h b/libs/binder/ParcelValTypes.h
index 666d22a..80736c8 100644
--- a/libs/binder/ParcelValTypes.h
+++ b/libs/binder/ParcelValTypes.h
@@ -27,18 +27,32 @@
VAL_PARCELABLE = 4,
VAL_SHORT = 5,
VAL_LONG = 6,
+ VAL_FLOAT = 7,
VAL_DOUBLE = 8,
VAL_BOOLEAN = 9,
+ VAL_CHARSEQUENCE = 10,
+ VAL_LIST = 11,
+ VAL_SPARSEARRAY = 12,
VAL_BYTEARRAY = 13,
VAL_STRINGARRAY = 14,
VAL_IBINDER = 15,
+ VAL_PARCELABLEARRAY = 16,
+ VAL_OBJECTARRAY = 17,
VAL_INTARRAY = 18,
VAL_LONGARRAY = 19,
VAL_BYTE = 20,
VAL_SERIALIZABLE = 21,
+ VAL_SPARSEBOOLEANARRAY = 22,
VAL_BOOLEANARRAY = 23,
+ VAL_CHARSEQUENCEARRAY = 24,
VAL_PERSISTABLEBUNDLE = 25,
+ VAL_SIZE = 26,
+ VAL_SIZEF = 27,
VAL_DOUBLEARRAY = 28,
+ VAL_CHAR = 29,
+ VAL_SHORTARRAY = 30,
+ VAL_CHARARRAY = 31,
+ VAL_FLOATARRAY = 32,
};
} // namespace binder
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index 2e86b74..3cf94e3 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -52,7 +52,10 @@
}
status_t ParcelableHolder::readFromParcel(const Parcel* p) {
- this->mStability = static_cast<Stability>(p->readInt32());
+ int32_t wireStability;
+ if (status_t status = p->readInt32(&wireStability); status != OK) return status;
+ if (static_cast<int32_t>(this->mStability) != wireStability) return BAD_VALUE;
+
this->mParcelable = nullptr;
this->mParcelableName = std::nullopt;
int32_t rawDataSize;
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index 406fee0..1504715 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -27,13 +27,6 @@
#include "ParcelValTypes.h"
-using android::BAD_TYPE;
-using android::BAD_VALUE;
-using android::NO_ERROR;
-using android::Parcel;
-using android::status_t;
-using android::UNEXPECTED_NULL;
-
using android::binder::VAL_BOOLEAN;
using android::binder::VAL_INTEGER;
using android::binder::VAL_LONG;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index bade918..4a01d81 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -18,14 +18,17 @@
#include <binder/ProcessState.h>
+#include <android-base/result.h>
+#include <android-base/strings.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Stability.h>
#include <cutils/atomic.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Thread.h>
#include "Static.h"
#include "binder_module.h"
@@ -88,13 +91,21 @@
return init(nullptr, false /*requireDefault*/);
}
+[[clang::no_destroy]] static sp<ProcessState> gProcess;
+[[clang::no_destroy]] static std::mutex gProcessMutex;
+
+static void verifyNotForked(bool forked) {
+ LOG_ALWAYS_FATAL_IF(forked, "libbinder ProcessState can not be used after fork");
+}
+
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
- [[clang::no_destroy]] static sp<ProcessState> gProcess;
- [[clang::no_destroy]] static std::mutex gProcessMutex;
if (driver == nullptr) {
std::lock_guard<std::mutex> l(gProcessMutex);
+ if (gProcess) {
+ verifyNotForked(gProcess->mForked);
+ }
return gProcess;
}
@@ -105,6 +116,14 @@
driver = "/dev/binder";
}
+ // we must install these before instantiating the gProcess object,
+ // otherwise this would race with creating it, and there could be the
+ // possibility of an invalid gProcess object forked by another thread
+ // before these are installed
+ int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
+ ProcessState::childPostFork);
+ LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
+
std::lock_guard<std::mutex> l(gProcessMutex);
gProcess = sp<ProcessState>::make(driver);
});
@@ -118,6 +137,7 @@
gProcess->getDriverName().c_str(), driver);
}
+ verifyNotForked(gProcess->mForked);
return gProcess;
}
@@ -136,10 +156,33 @@
return context;
}
+void ProcessState::onFork() {
+ // make sure another thread isn't currently retrieving ProcessState
+ gProcessMutex.lock();
+}
+
+void ProcessState::parentPostFork() {
+ gProcessMutex.unlock();
+}
+
+void ProcessState::childPostFork() {
+ // another thread might call fork before gProcess is instantiated, but after
+ // the thread handler is installed
+ if (gProcess) {
+ gProcess->mForked = true;
+ }
+ gProcessMutex.unlock();
+}
+
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
+ if (mMaxThreads == 0) {
+ ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
+ "*startThreadPool when zero threads are requested.");
+ }
+
mThreadPoolStarted = true;
spawnPooledThread(true);
}
@@ -211,7 +254,7 @@
binder_node_info_for_ref info;
memset(&info, 0, sizeof(binder_node_info_for_ref));
- info.handle = binder->getPrivateAccessorForId().binderHandle();
+ info.handle = binder->getPrivateAccessor().binderHandle();
status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
@@ -279,11 +322,6 @@
//
// Note that this is not race-free if the context manager
// dies while this code runs.
- //
- // TODO: add a driver API to wait for context manager, or
- // stop special casing handle 0 for context manager and add
- // a driver API to get a handle to the context manager with
- // proper reference counting.
IPCThreadState* ipc = IPCThreadState::self();
@@ -300,7 +338,7 @@
return nullptr;
}
- sp<BpBinder> b = BpBinder::create(handle);
+ sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
@@ -331,8 +369,13 @@
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
pid_t pid = getpid();
+
+ std::string_view driverName = mDriverName.c_str();
+ android::base::ConsumePrefix(&driverName, "/dev/");
+
String8 name;
- name.appendFormat("Binder:%d_%X", pid, s);
+ name.appendFormat("%.*s:%d_%X", static_cast<int>(driverName.length()), driverName.data(), pid,
+ s);
return name;
}
@@ -359,6 +402,36 @@
return result;
}
+size_t ProcessState::getThreadPoolMaxThreadCount() const {
+ // may actually be one more than this, if join is called
+ if (mThreadPoolStarted) return mMaxThreads;
+ // must not be initialized or maybe has poll thread setup, we
+ // currently don't track this in libbinder
+ return 0;
+}
+
+#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
+bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
+ static const char* const names[] = {
+ [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
+ DRIVER_FEATURES_PATH "oneway_spam_detection",
+ };
+ int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
+ char on;
+ if (fd == -1) {
+ ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ if (read(fd, &on, sizeof(on)) == -1) {
+ ALOGE("%s: error reading to %s: %s", __func__,
+ names[static_cast<int>(feature)], strerror(errno));
+ return false;
+ }
+ close(fd);
+ return on == '1';
+}
+
status_t ProcessState::enableOnewaySpamDetection(bool enable) {
uint32_t enableDetection = enable ? 1 : 0;
if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
@@ -376,68 +449,76 @@
return mDriverName;
}
-static int open_driver(const char *driver)
-{
+static base::Result<int> open_driver(const char* driver) {
int fd = open(driver, O_RDWR | O_CLOEXEC);
- if (fd >= 0) {
- int vers = 0;
- status_t result = ioctl(fd, BINDER_VERSION, &vers);
- if (result == -1) {
- ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
- close(fd);
- fd = -1;
- }
- if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
- ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
- vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
- close(fd);
- fd = -1;
- }
- size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
- result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
- 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) {
- ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
- }
- } else {
- ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
+ if (fd < 0) {
+ return base::ErrnoError() << "Opening '" << driver << "' failed";
+ }
+ int vers = 0;
+ status_t result = ioctl(fd, BINDER_VERSION, &vers);
+ if (result == -1) {
+ close(fd);
+ return base::ErrnoError() << "Binder ioctl to obtain version failed";
+ }
+ if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+ close(fd);
+ return base::Error() << "Binder driver protocol(" << vers
+ << ") does not match user space protocol("
+ << BINDER_CURRENT_PROTOCOL_VERSION
+ << ")! ioctl() return value: " << result;
+ }
+ size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
+ result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+ 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) {
+ ALOGE_IF(ProcessState::isDriverFeatureEnabled(
+ ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
+ "Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
return fd;
}
-ProcessState::ProcessState(const char *driver)
- : mDriverName(String8(driver))
- , mDriverFD(open_driver(driver))
- , mVMStart(MAP_FAILED)
- , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
- , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
- , mExecutingThreadsCount(0)
- , mWaitingForThreads(0)
- , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
- , mStarvationStartTimeMs(0)
- , mThreadPoolStarted(false)
- , mThreadPoolSeq(1)
- , mCallRestriction(CallRestriction::NONE)
-{
- if (mDriverFD >= 0) {
+ProcessState::ProcessState(const char* driver)
+ : mDriverName(String8(driver)),
+ mDriverFD(-1),
+ mVMStart(MAP_FAILED),
+ mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
+ mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
+ mExecutingThreadsCount(0),
+ mWaitingForThreads(0),
+ mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
+ mStarvationStartTimeMs(0),
+ mForked(false),
+ mThreadPoolStarted(false),
+ mThreadPoolSeq(1),
+ mCallRestriction(CallRestriction::NONE) {
+ base::Result<int> opened = open_driver(driver);
+
+ if (opened.ok()) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
- mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+ mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
+ opened.value(), 0);
if (mVMStart == MAP_FAILED) {
+ close(opened.value());
// *sigh*
- ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
- close(mDriverFD);
- mDriverFD = -1;
+ opened = base::Error()
+ << "Using " << driver << " failed: unable to mmap transaction memory.";
mDriverName.clear();
}
}
#ifdef __ANDROID__
- LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened. Terminating.", driver);
+ LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating: %s",
+ driver, opened.error().message().c_str());
#endif
+
+ if (opened.ok()) {
+ mDriverFD = opened.value();
+ }
}
ProcessState::~ProcessState()
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
deleted file mode 100644
index 5c32320..0000000
--- a/libs/binder/RpcAddress.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 9cc6e7f..ace5cd5 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -16,57 +16,67 @@
#define LOG_TAG "RpcServer"
+#include <inttypes.h>
+#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <thread>
#include <vector>
+#include <android-base/file.h>
+#include <android-base/hex.h>
#include <android-base/scopeguard.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <log/log.h>
-#include "RpcState.h"
+#include "FdTrigger.h"
#include "RpcSocketAddress.h"
+#include "RpcState.h"
#include "RpcWireFormat.h"
namespace android {
+constexpr size_t kSessionIdBytes = 32;
+
using base::ScopeGuard;
using base::unique_fd;
-RpcServer::RpcServer() {}
-RpcServer::~RpcServer() {}
-
-sp<RpcServer> RpcServer::make() {
- return sp<RpcServer>::make();
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
+RpcServer::~RpcServer() {
+ (void)shutdown();
}
-void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
- mAgreedExperimental = true;
+sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+ // Default is without TLS.
+ if (rpcTransportCtxFactory == nullptr)
+ rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+ auto ctx = rpcTransportCtxFactory->newServerCtx();
+ if (ctx == nullptr) return nullptr;
+ return sp<RpcServer>::make(std::move(ctx));
}
-bool RpcServer::setupUnixDomainServer(const char* path) {
+status_t RpcServer::setupUnixDomainServer(const char* path) {
return setupSocketServer(UnixSocketAddress(path));
}
-bool RpcServer::setupVsockServer(unsigned int port) {
+status_t RpcServer::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 RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
- const char* kAddr = "127.0.0.1";
-
+status_t RpcServer::setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort) {
if (assignedPort != nullptr) *assignedPort = 0;
- auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
- if (aiStart == nullptr) return false;
+ auto aiStart = InetSocketAddress::getAddrInfo(address, port);
+ if (aiStart == nullptr) return UNKNOWN_ERROR;
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
- if (!setupSocketServer(socketAddress)) {
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port);
+ if (status_t status = setupSocketServer(socketAddress); status != OK) {
continue;
}
@@ -77,7 +87,7 @@
int savedErrno = errno;
ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
strerror(savedErrno));
- return false;
+ return -savedErrno;
}
LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
static_cast<size_t>(len), sizeof(addr));
@@ -90,16 +100,16 @@
*assignedPort = realPort;
}
- return true;
+ return OK;
}
- ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
+ ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", address,
port);
- return false;
+ return UNKNOWN_ERROR;
}
void RpcServer::setMaxThreads(size_t threads) {
LOG_ALWAYS_FATAL_IF(threads <= 0, "RpcServer is useless without threads");
- LOG_ALWAYS_FATAL_IF(mStarted, "must be called before started");
+ LOG_ALWAYS_FATAL_IF(mJoinThreadRunning, "Cannot set max threads while running");
mMaxThreads = threads;
}
@@ -107,16 +117,29 @@
return mMaxThreads;
}
+void RpcServer::setProtocolVersion(uint32_t version) {
+ mProtocolVersion = version;
+}
+
void RpcServer::setRootObject(const sp<IBinder>& binder) {
std::lock_guard<std::mutex> _l(mLock);
+ mRootObjectFactory = nullptr;
mRootObjectWeak = mRootObject = binder;
}
void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
std::lock_guard<std::mutex> _l(mLock);
mRootObject.clear();
+ mRootObjectFactory = nullptr;
mRootObjectWeak = binder;
}
+void RpcServer::setPerSessionRootObject(
+ std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& makeObject) {
+ std::lock_guard<std::mutex> _l(mLock);
+ mRootObject.clear();
+ mRootObjectWeak.clear();
+ mRootObjectFactory = std::move(makeObject);
+}
sp<IBinder> RpcServer::getRootObject() {
std::lock_guard<std::mutex> _l(mLock);
@@ -126,33 +149,105 @@
return ret;
}
-void RpcServer::join() {
- while (true) {
- (void)acceptOne();
- }
+std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
+ std::lock_guard<std::mutex> _l(mLock);
+ return mCtx->getCertificate(format);
}
-bool RpcServer::acceptOne() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
- LOG_ALWAYS_FATAL_IF(!hasServer(), "RpcServer must be setup to join.");
+static void joinRpcServer(sp<RpcServer>&& thiz) {
+ thiz->join();
+}
- unique_fd clientFd(
- TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
+void RpcServer::start() {
+ std::lock_guard<std::mutex> _l(mLock);
+ LOG_ALWAYS_FATAL_IF(mJoinThread.get(), "Already started!");
+ mJoinThread = std::make_unique<std::thread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
+}
- if (clientFd < 0) {
- ALOGE("Could not accept4 socket: %s", strerror(errno));
- return false;
- }
- LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+void RpcServer::join() {
{
std::lock_guard<std::mutex> _l(mLock);
- std::thread thread =
- std::thread(&RpcServer::establishConnection, this,
- std::move(sp<RpcServer>::fromExisting(this)), std::move(clientFd));
- mConnectingThreads[thread.get_id()] = std::move(thread);
+ LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
+ mJoinThreadRunning = true;
+ mShutdownTrigger = FdTrigger::make();
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
}
+ status_t status;
+ while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
+ sockaddr_storage addr;
+ socklen_t addrLen = sizeof(addr);
+
+ unique_fd clientFd(
+ TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(&addr),
+ &addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+
+ LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(addr)), "Truncated address");
+
+ if (clientFd < 0) {
+ ALOGE("Could not accept4 socket: %s", strerror(errno));
+ continue;
+ }
+ LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ std::thread thread =
+ std::thread(&RpcServer::establishConnection, sp<RpcServer>::fromExisting(this),
+ std::move(clientFd), addr, addrLen);
+ mConnectingThreads[thread.get_id()] = std::move(thread);
+ }
+ }
+ LOG_RPC_DETAIL("RpcServer::join exiting with %s", statusToString(status).c_str());
+
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ mJoinThreadRunning = false;
+ }
+ mShutdownCv.notify_all();
+}
+
+bool RpcServer::shutdown() {
+ std::unique_lock<std::mutex> _l(mLock);
+ if (mShutdownTrigger == nullptr) {
+ LOG_RPC_DETAIL("Cannot shutdown. No shutdown trigger installed (already shutdown?)");
+ return false;
+ }
+
+ mShutdownTrigger->trigger();
+
+ for (auto& [id, session] : mSessions) {
+ (void)id;
+ // server lock is a more general lock
+ std::lock_guard<std::mutex> _lSession(session->mMutex);
+ session->mShutdownTrigger->trigger();
+ }
+
+ while (mJoinThreadRunning || !mConnectingThreads.empty() || !mSessions.empty()) {
+ if (std::cv_status::timeout == mShutdownCv.wait_for(_l, std::chrono::seconds(1))) {
+ ALOGE("Waiting for RpcServer to shut down (1s w/o progress). Join thread running: %d, "
+ "Connecting threads: "
+ "%zu, Sessions: %zu. Is your server deadlocked?",
+ mJoinThreadRunning, mConnectingThreads.size(), mSessions.size());
+ }
+ }
+
+ // At this point, we know join() is about to exit, but the thread that calls
+ // join() may not have exited yet.
+ // If RpcServer owns the join thread (aka start() is called), make sure the thread exits;
+ // otherwise ~thread() may call std::terminate(), which may crash the process.
+ // If RpcServer does not own the join thread (aka join() is called directly),
+ // then the owner of RpcServer is responsible for cleaning up that thread.
+ if (mJoinThread.get()) {
+ mJoinThread->join();
+ mJoinThread.reset();
+ }
+
+ LOG_RPC_DETAIL("Finished waiting on shutdown.");
+
+ mShutdownTrigger = nullptr;
return true;
}
@@ -171,127 +266,255 @@
return mConnectingThreads.size();
}
-void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd) {
- LOG_ALWAYS_FATAL_IF(this != server.get(), "Must pass same ownership object");
+void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
+ const sockaddr_storage addr, socklen_t addrLen) {
+ // mShutdownTrigger can only be cleared once connection threads have joined.
+ // It must be set before this thread is started
+ LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
+ LOG_ALWAYS_FATAL_IF(server->mCtx == nullptr);
- // TODO(b/183988761): cannot trust this simple ID
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
- bool idValid = true;
- int32_t id;
- if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
- ALOGE("Could not read ID from fd %d", clientFd.get());
- idValid = false;
+ status_t status = OK;
+
+ int clientFdForLog = clientFd.get();
+ auto client = server->mCtx->newTransport(std::move(clientFd), server->mShutdownTrigger.get());
+ if (client == nullptr) {
+ ALOGE("Dropping accept4()-ed socket because sslAccept fails");
+ status = DEAD_OBJECT;
+ // still need to cleanup before we can return
+ } else {
+ LOG_RPC_DETAIL("Created RpcTransport %p for client fd %d", client.get(), clientFdForLog);
+ }
+
+ RpcConnectionHeader header;
+ if (status == OK) {
+ iovec iov{&header, sizeof(header)};
+ status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
+ if (status != OK) {
+ ALOGE("Failed to read ID for client connecting to RPC server: %s",
+ statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
+ }
+
+ std::vector<uint8_t> sessionId;
+ if (status == OK) {
+ if (header.sessionIdSize > 0) {
+ if (header.sessionIdSize == kSessionIdBytes) {
+ sessionId.resize(header.sessionIdSize);
+ iovec iov{sessionId.data(), sessionId.size()};
+ status =
+ client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
+ if (status != OK) {
+ ALOGE("Failed to read session ID for client connecting to RPC server: %s",
+ statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
+ } else {
+ ALOGE("Malformed session ID. Expecting session ID of size %zu but got %" PRIu16,
+ kSessionIdBytes, header.sessionIdSize);
+ status = BAD_VALUE;
+ }
+ }
+ }
+
+ bool incoming = false;
+ uint32_t protocolVersion = 0;
+ bool requestingNewSession = false;
+
+ if (status == OK) {
+ incoming = header.options & RPC_CONNECTION_OPTION_INCOMING;
+ protocolVersion = std::min(header.version,
+ server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION));
+ requestingNewSession = sessionId.empty();
+
+ if (requestingNewSession) {
+ RpcNewSessionResponse response{
+ .version = protocolVersion,
+ };
+
+ iovec iov{&response, sizeof(response)};
+ status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1, {});
+ if (status != OK) {
+ ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
+ // still need to cleanup before we can return
+ }
+ }
}
std::thread thisThread;
sp<RpcSession> session;
{
- std::lock_guard<std::mutex> _l(mLock);
+ std::unique_lock<std::mutex> _l(server->mLock);
- auto threadId = mConnectingThreads.find(std::this_thread::get_id());
- LOG_ALWAYS_FATAL_IF(threadId == mConnectingThreads.end(),
+ auto threadId = server->mConnectingThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(threadId == server->mConnectingThreads.end(),
"Must establish connection on owned thread");
thisThread = std::move(threadId->second);
- ScopeGuard detachGuard = [&]() { thisThread.detach(); };
- mConnectingThreads.erase(threadId);
+ ScopeGuard detachGuard = [&]() {
+ thisThread.detach();
+ _l.unlock();
+ server->mShutdownCv.notify_all();
+ };
+ server->mConnectingThreads.erase(threadId);
- if (!idValid) {
+ if (status != OK || server->mShutdownTrigger->isTriggered()) {
return;
}
- if (id == RPC_SESSION_ID_NEW) {
- LOG_ALWAYS_FATAL_IF(mSessionIdCounter >= INT32_MAX, "Out of session IDs");
- mSessionIdCounter++;
+ if (requestingNewSession) {
+ if (incoming) {
+ ALOGE("Cannot create a new session with an incoming connection, would leak");
+ return;
+ }
+
+ // Uniquely identify session at the application layer. Even if a
+ // client/server use the same certificates, if they create multiple
+ // sessions, we still want to distinguish between them.
+ sessionId.resize(kSessionIdBytes);
+ size_t tries = 0;
+ do {
+ // don't block if there is some entropy issue
+ if (tries++ > 5) {
+ ALOGE("Cannot find new address: %s",
+ base::HexString(sessionId.data(), sessionId.size()).c_str());
+ return;
+ }
+
+ base::unique_fd fd(TEMP_FAILURE_RETRY(
+ open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
+ if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) {
+ ALOGE("Could not read from /dev/urandom to create session ID");
+ return;
+ }
+ } while (server->mSessions.end() != server->mSessions.find(sessionId));
session = RpcSession::make();
- session->setForServer(wp<RpcServer>::fromExisting(this), mSessionIdCounter);
+ session->setMaxIncomingThreads(server->mMaxThreads);
+ if (!session->setProtocolVersion(protocolVersion)) return;
- mSessions[mSessionIdCounter] = session;
+ // if null, falls back to server root
+ sp<IBinder> sessionSpecificRoot;
+ if (server->mRootObjectFactory != nullptr) {
+ sessionSpecificRoot =
+ server->mRootObjectFactory(reinterpret_cast<const sockaddr*>(&addr),
+ addrLen);
+ if (sessionSpecificRoot == nullptr) {
+ ALOGE("Warning: server returned null from root object factory");
+ }
+ }
+
+ if (!session->setForServer(server,
+ sp<RpcServer::EventListener>::fromExisting(
+ static_cast<RpcServer::EventListener*>(
+ server.get())),
+ sessionId, sessionSpecificRoot)) {
+ ALOGE("Failed to attach server to session");
+ return;
+ }
+
+ server->mSessions[sessionId] = session;
} else {
- auto it = mSessions.find(id);
- if (it == mSessions.end()) {
- ALOGE("Cannot add thread, no record of session with ID %d", id);
+ auto it = server->mSessions.find(sessionId);
+ if (it == server->mSessions.end()) {
+ ALOGE("Cannot add thread, no record of session with ID %s",
+ base::HexString(sessionId.data(), sessionId.size()).c_str());
return;
}
session = it->second;
}
+ if (incoming) {
+ LOG_ALWAYS_FATAL_IF(OK != session->addOutgoingConnection(std::move(client), true),
+ "server state must already be initialized");
+ return;
+ }
+
detachGuard.Disable();
- session->preJoin(std::move(thisThread));
+ session->preJoinThreadOwnership(std::move(thisThread));
}
+ auto setupResult = session->preJoinSetup(std::move(client));
+
// avoid strong cycle
server = nullptr;
- //
- //
- // DO NOT ACCESS MEMBER VARIABLES BELOW
- //
- session->join(std::move(clientFd));
+ RpcSession::join(std::move(session), std::move(setupResult));
}
-bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ unique_fd serverFd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
if (serverFd == -1) {
- ALOGE("Could not create socket: %s", strerror(errno));
- return false;
+ int savedErrno = errno;
+ ALOGE("Could not create socket: %s", strerror(savedErrno));
+ return -savedErrno;
}
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;
+ return -savedErrno;
}
- if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+ // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
+ // the backlog is increased to a large number.
+ // TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
+ // to 1.
+ if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 50 /*backlog*/))) {
int savedErrno = errno;
ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
- return false;
+ return -savedErrno;
}
LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
- mServer = std::move(serverFd);
- return true;
+ if (status_t status = setupExternalServer(std::move(serverFd)); status != OK) {
+ ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
+ return status;
+ }
+ return OK;
}
-void RpcServer::onSessionTerminating(const sp<RpcSession>& session) {
- auto id = session->mId;
- LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
- LOG_RPC_DETAIL("Dropping session %d", *id);
+void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
+ const std::vector<uint8_t>& id = session->mId;
+ LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID");
+ LOG_RPC_DETAIL("Dropping session with address %s",
+ base::HexString(id.data(), id.size()).c_str());
std::lock_guard<std::mutex> _l(mLock);
- auto it = mSessions.find(*id);
- LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %d", *id);
- LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %d", *id);
+ auto it = mSessions.find(id);
+ LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s",
+ base::HexString(id.data(), id.size()).c_str());
+ LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s",
+ base::HexString(id.data(), id.size()).c_str());
(void)mSessions.erase(it);
}
+void RpcServer::onSessionIncomingThreadEnded() {
+ mShutdownCv.notify_all();
+}
+
bool RpcServer::hasServer() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
return mServer.ok();
}
unique_fd RpcServer::releaseServer() {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
std::lock_guard<std::mutex> _l(mLock);
return std::move(mServer);
}
-bool RpcServer::setupExternalServer(base::unique_fd serverFd) {
- LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
std::lock_guard<std::mutex> _l(mLock);
if (mServer.ok()) {
ALOGE("Each RpcServer can only have one server.");
- return false;
+ return INVALID_OPERATION;
}
mServer = std::move(serverFd);
- return true;
+ return OK;
}
} // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 05fa49e..d40778a 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -18,99 +18,239 @@
#include <binder/RpcSession.h>
+#include <dlfcn.h>
#include <inttypes.h>
+#include <poll.h>
+#include <pthread.h>
#include <unistd.h>
#include <string_view>
+#include <android-base/hex.h>
+#include <android-base/macros.h>
+#include <android-base/scopeguard.h>
+#include <binder/BpBinder.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
#include <binder/Stability.h>
#include <utils/String8.h>
+#include "FdTrigger.h"
#include "RpcSocketAddress.h"
#include "RpcState.h"
#include "RpcWireFormat.h"
+#include "Utils.h"
#ifdef __GLIBC__
extern "C" pid_t gettid();
#endif
+#ifndef __ANDROID_RECOVERY__
+#include <android_runtime/vm.h>
+#include <jni.h>
+#endif
+
namespace android {
using base::unique_fd;
-RpcSession::RpcSession() {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {
LOG_RPC_DETAIL("RpcSession created %p", this);
- mState = std::make_unique<RpcState>();
+ mRpcBinderState = std::make_unique<RpcState>();
}
RpcSession::~RpcSession() {
LOG_RPC_DETAIL("RpcSession destroyed %p", this);
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mServerConnections.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mConnections.mIncoming.size() != 0,
"Should not be able to destroy a session with servers in use.");
}
sp<RpcSession> RpcSession::make() {
- return sp<RpcSession>::make();
+ // Default is without TLS.
+ return make(RpcTransportCtxFactoryRaw::make());
}
-bool RpcSession::setupUnixDomainClient(const char* path) {
- return setupSocketClient(UnixSocketAddress(path));
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+ auto ctx = rpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) return nullptr;
+ return sp<RpcSession>::make(std::move(ctx));
}
-bool RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
- return setupSocketClient(VsockSocketAddress(cid, port));
+void RpcSession::setMaxIncomingThreads(size_t threads) {
+ std::lock_guard<std::mutex> _l(mMutex);
+ LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
+ "Must set max incoming threads before setting up connections, but has %zu "
+ "client(s) and %zu server(s)",
+ mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+ mMaxIncomingThreads = threads;
}
-bool RpcSession::setupInetClient(const char* addr, unsigned int port) {
- auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
- if (aiStart == nullptr) return false;
- for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
- if (setupSocketClient(socketAddress)) return true;
- }
- ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
- return false;
+size_t RpcSession::getMaxIncomingThreads() {
+ std::lock_guard<std::mutex> _l(mMutex);
+ return mMaxIncomingThreads;
}
-bool RpcSession::addNullDebuggingClient() {
- unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
+void RpcSession::setMaxOutgoingThreads(size_t threads) {
+ std::lock_guard<std::mutex> _l(mMutex);
+ LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
+ "Must set max outgoing threads before setting up connections, but has %zu "
+ "client(s) and %zu server(s)",
+ mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+ mMaxOutgoingThreads = threads;
+}
- if (serverFd == -1) {
- ALOGE("Could not connect to /dev/null: %s", strerror(errno));
+size_t RpcSession::getMaxOutgoingThreads() {
+ std::lock_guard<std::mutex> _l(mMutex);
+ return mMaxOutgoingThreads;
+}
+
+bool RpcSession::setProtocolVersion(uint32_t version) {
+ if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
+ version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+ ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version "
+ "is %u).",
+ version, RPC_WIRE_PROTOCOL_VERSION);
return false;
}
- addClientConnection(std::move(serverFd));
+ std::lock_guard<std::mutex> _l(mMutex);
+ if (mProtocolVersion && version > *mProtocolVersion) {
+ ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
+ *mProtocolVersion, version);
+ return false;
+ }
+
+ mProtocolVersion = version;
return true;
}
+std::optional<uint32_t> RpcSession::getProtocolVersion() {
+ std::lock_guard<std::mutex> _l(mMutex);
+ return mProtocolVersion;
+}
+
+status_t RpcSession::setupUnixDomainClient(const char* path) {
+ return setupSocketClient(UnixSocketAddress(path));
+}
+
+status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
+ return setupSocketClient(VsockSocketAddress(cid, port));
+}
+
+status_t RpcSession::setupInetClient(const char* addr, unsigned int port) {
+ auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
+ if (aiStart == nullptr) return UNKNOWN_ERROR;
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
+ if (status_t status = setupSocketClient(socketAddress); status == OK) return OK;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
+ return NAME_NOT_FOUND;
+}
+
+status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
+ // Why passing raw fd? When fd is passed as reference, Clang analyzer sees that the variable
+ // `fd` is a moved-from object. To work-around the issue, unwrap the raw fd from the outer `fd`,
+ // pass the raw fd by value to the lambda, and then finally wrap it in unique_fd inside the
+ // lambda.
+ return setupClient([&, raw = fd.release()](const std::vector<uint8_t>& sessionId,
+ bool incoming) -> status_t {
+ unique_fd fd(raw);
+ if (!fd.ok()) {
+ fd = request();
+ if (!fd.ok()) return BAD_VALUE;
+ }
+ if (auto res = setNonBlocking(fd); !res.ok()) {
+ ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
+ return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
+ }
+ return initAndAddConnection(std::move(fd), sessionId, incoming);
+ });
+}
+
+status_t RpcSession::addNullDebuggingClient() {
+ // Note: only works on raw sockets.
+ if (auto status = initShutdownTrigger(); status != OK) return status;
+
+ unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
+
+ if (serverFd == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not connect to /dev/null: %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+
+ auto server = mCtx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+ if (server == nullptr) {
+ ALOGE("Unable to set up RpcTransport");
+ return UNKNOWN_ERROR;
+ }
+ return addOutgoingConnection(std::move(server), false);
+}
+
sp<IBinder> RpcSession::getRootObject() {
- ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
- return state()->getRootObject(connection.fd(), sp<RpcSession>::fromExisting(this));
+ ExclusiveConnection connection;
+ status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
+ if (status != OK) return nullptr;
+ return state()->getRootObject(connection.get(), sp<RpcSession>::fromExisting(this));
}
status_t RpcSession::getRemoteMaxThreads(size_t* maxThreads) {
- ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
- return state()->getMaxThreads(connection.fd(), sp<RpcSession>::fromExisting(this), maxThreads);
+ ExclusiveConnection connection;
+ status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
+ if (status != OK) return status;
+ return state()->getMaxThreads(connection.get(), sp<RpcSession>::fromExisting(this), maxThreads);
}
-status_t RpcSession::transact(const RpcAddress& address, uint32_t code, const Parcel& data,
+bool RpcSession::shutdownAndWait(bool wait) {
+ std::unique_lock<std::mutex> _l(mMutex);
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Shutdown trigger not installed");
+
+ mShutdownTrigger->trigger();
+
+ if (wait) {
+ LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
+ mShutdownListener->waitForShutdown(_l, sp<RpcSession>::fromExisting(this));
+
+ LOG_ALWAYS_FATAL_IF(!mConnections.mThreads.empty(), "Shutdown failed");
+ }
+
+ _l.unlock();
+ mRpcBinderState->clear();
+
+ return true;
+}
+
+status_t RpcSession::transact(const sp<IBinder>& binder, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
- ExclusiveConnection connection(sp<RpcSession>::fromExisting(this),
- (flags & IBinder::FLAG_ONEWAY) ? ConnectionUse::CLIENT_ASYNC
- : ConnectionUse::CLIENT);
- return state()->transact(connection.fd(), address, code, data,
+ ExclusiveConnection connection;
+ status_t status =
+ ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ (flags & IBinder::FLAG_ONEWAY) ? ConnectionUse::CLIENT_ASYNC
+ : ConnectionUse::CLIENT,
+ &connection);
+ if (status != OK) return status;
+ return state()->transact(connection.get(), binder, code, data,
sp<RpcSession>::fromExisting(this), reply, flags);
}
-status_t RpcSession::sendDecStrong(const RpcAddress& address) {
- ExclusiveConnection connection(sp<RpcSession>::fromExisting(this),
- ConnectionUse::CLIENT_REFCOUNT);
- return state()->sendDecStrong(connection.fd(), address);
+status_t RpcSession::sendDecStrong(const BpBinder* binder) {
+ // target is 0 because this is used to free BpBinder objects
+ return sendDecStrongToTarget(binder->getPrivateAccessor().rpcAddress(), 0 /*target*/);
+}
+
+status_t RpcSession::sendDecStrongToTarget(uint64_t address, size_t target) {
+ ExclusiveConnection connection;
+ status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT_REFCOUNT, &connection);
+ if (status != OK) return status;
+ return state()->sendDecStrongToTarget(connection.get(), sp<RpcSession>::fromExisting(this),
+ address, target);
}
status_t RpcSession::readId() {
@@ -119,204 +259,552 @@
LOG_ALWAYS_FATAL_IF(mForServer != nullptr, "Can only update ID for client.");
}
- int32_t id;
-
- ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
- status_t status =
- state()->getSessionId(connection.fd(), sp<RpcSession>::fromExisting(this), &id);
+ ExclusiveConnection connection;
+ status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
if (status != OK) return status;
- LOG_RPC_DETAIL("RpcSession %p has id %d", this, id);
- mId = id;
+ status = state()->getSessionId(connection.get(), sp<RpcSession>::fromExisting(this), &mId);
+ if (status != OK) return status;
+
+ LOG_RPC_DETAIL("RpcSession %p has id %s", this,
+ base::HexString(mId.data(), mId.size()).c_str());
return OK;
}
-void RpcSession::preJoin(std::thread thread) {
+void RpcSession::WaitForShutdownListener::onSessionAllIncomingThreadsEnded(
+ const sp<RpcSession>& session) {
+ (void)session;
+}
+
+void RpcSession::WaitForShutdownListener::onSessionIncomingThreadEnded() {
+ mCv.notify_all();
+}
+
+void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
+ const sp<RpcSession>& session) {
+ while (session->mConnections.mIncoming.size() > 0) {
+ if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
+ ALOGE("Waiting for RpcSession to shut down (1s w/o progress): %zu incoming connections "
+ "still.",
+ session->mConnections.mIncoming.size());
+ }
+ }
+}
+
+void RpcSession::preJoinThreadOwnership(std::thread thread) {
LOG_ALWAYS_FATAL_IF(thread.get_id() != std::this_thread::get_id(), "Must own this thread");
{
std::lock_guard<std::mutex> _l(mMutex);
- mThreads[thread.get_id()] = std::move(thread);
+ mConnections.mThreads[thread.get_id()] = std::move(thread);
}
}
-void RpcSession::join(unique_fd client) {
+RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(
+ std::unique_ptr<RpcTransport> rpcTransport) {
// 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<RpcConnection> connection = assignServerToThisThread(std::move(client));
+ sp<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(rpcTransport));
- while (true) {
- status_t error =
- state()->getAndExecuteCommand(connection->fd, sp<RpcSession>::fromExisting(this));
+ status_t status;
- if (error != OK) {
- ALOGI("Binder connection thread closing w/ status %s", statusToString(error).c_str());
- break;
+ if (connection == nullptr) {
+ status = DEAD_OBJECT;
+ } else {
+ status =
+ mRpcBinderState->readConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+ }
+
+ return PreJoinSetupResult{
+ .connection = std::move(connection),
+ .status = status,
+ };
+}
+
+namespace {
+#ifdef __ANDROID_RECOVERY__
+class JavaThreadAttacher {};
+#else
+// RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
+// Android Runtime doesn't exist, no-op.
+class JavaThreadAttacher {
+public:
+ JavaThreadAttacher() {
+ // Use dlsym to find androidJavaAttachThread because libandroid_runtime is loaded after
+ // libbinder.
+ auto vm = getJavaVM();
+ if (vm == nullptr) return;
+
+ char threadName[16];
+ if (0 != pthread_getname_np(pthread_self(), threadName, sizeof(threadName))) {
+ constexpr const char* defaultThreadName = "UnknownRpcSessionThread";
+ memcpy(threadName, defaultThreadName,
+ std::min<size_t>(sizeof(threadName), strlen(defaultThreadName) + 1));
+ }
+ LOG_RPC_DETAIL("Attaching current thread %s to JVM", threadName);
+ JavaVMAttachArgs args;
+ args.version = JNI_VERSION_1_2;
+ args.name = threadName;
+ args.group = nullptr;
+ JNIEnv* env;
+
+ LOG_ALWAYS_FATAL_IF(vm->AttachCurrentThread(&env, &args) != JNI_OK,
+ "Cannot attach thread %s to JVM", threadName);
+ mAttached = true;
+ }
+ ~JavaThreadAttacher() {
+ if (!mAttached) return;
+ auto vm = getJavaVM();
+ LOG_ALWAYS_FATAL_IF(vm == nullptr,
+ "Unable to detach thread. No JavaVM, but it was present before!");
+
+ LOG_RPC_DETAIL("Detaching current thread from JVM");
+ if (vm->DetachCurrentThread() != JNI_OK) {
+ mAttached = false;
+ } else {
+ ALOGW("Unable to detach current thread from JVM");
}
}
- LOG_ALWAYS_FATAL_IF(!removeServerConnection(connection),
- "bad state: connection object guaranteed to be in list");
+private:
+ DISALLOW_COPY_AND_ASSIGN(JavaThreadAttacher);
+ bool mAttached = false;
+ static JavaVM* getJavaVM() {
+ static auto fn = reinterpret_cast<decltype(&AndroidRuntimeGetJavaVM)>(
+ dlsym(RTLD_DEFAULT, "AndroidRuntimeGetJavaVM"));
+ if (fn == nullptr) return nullptr;
+ return fn();
+ }
+};
+#endif
+} // namespace
+
+void RpcSession::join(sp<RpcSession>&& session, PreJoinSetupResult&& setupResult) {
+ sp<RpcConnection>& connection = setupResult.connection;
+
+ if (setupResult.status == OK) {
+ LOG_ALWAYS_FATAL_IF(!connection, "must have connection if setup succeeded");
+ [[maybe_unused]] JavaThreadAttacher javaThreadAttacher;
+ while (true) {
+ status_t status = session->state()->getAndExecuteCommand(connection, session,
+ RpcState::CommandType::ANY);
+ if (status != OK) {
+ LOG_RPC_DETAIL("Binder connection thread closing w/ status %s",
+ statusToString(status).c_str());
+ break;
+ }
+ }
+ } else {
+ ALOGE("Connection failed to init, closing with status %s",
+ statusToString(setupResult.status).c_str());
+ }
+
+ sp<RpcSession::EventListener> listener;
{
- std::lock_guard<std::mutex> _l(mMutex);
- auto it = mThreads.find(std::this_thread::get_id());
- LOG_ALWAYS_FATAL_IF(it == mThreads.end());
+ std::lock_guard<std::mutex> _l(session->mMutex);
+ auto it = session->mConnections.mThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(it == session->mConnections.mThreads.end());
it->second.detach();
- mThreads.erase(it);
+ session->mConnections.mThreads.erase(it);
+
+ listener = session->mEventListener.promote();
+ }
+
+ // done after all cleanup, since session shutdown progresses via callbacks here
+ if (connection != nullptr) {
+ LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
+ "bad state: connection object guaranteed to be in list");
+ }
+
+ session = nullptr;
+
+ if (listener != nullptr) {
+ listener->onSessionIncomingThreadEnded();
}
}
-void RpcSession::terminateLocked() {
- // TODO(b/185167543):
- // - kindly notify other side of the connection of termination (can't be
- // locked)
- // - prevent new client/servers from being added
- // - stop all threads which are currently reading/writing
- // - terminate RpcState?
-
- if (mTerminated) return;
-
+sp<RpcServer> RpcSession::server() {
+ RpcServer* unsafeServer = mForServer.unsafe_get();
sp<RpcServer> server = mForServer.promote();
- if (server) {
- server->onSessionTerminating(sp<RpcSession>::fromExisting(this));
- }
+
+ LOG_ALWAYS_FATAL_IF((unsafeServer == nullptr) != (server == nullptr),
+ "wp<> is to avoid strong cycle only");
+ return server;
}
-wp<RpcServer> RpcSession::server() {
- return mForServer;
-}
-
-bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
+ bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mClientConnections.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
"Must only setup session once, but already has %zu clients",
- mClientConnections.size());
+ mConnections.mOutgoing.size());
}
- if (!setupOneSocketClient(addr, RPC_SESSION_ID_NEW)) return false;
+ if (auto status = initShutdownTrigger(); status != OK) return status;
- // TODO(b/185167543): we should add additional sessions dynamically
+ auto oldProtocolVersion = mProtocolVersion;
+ auto cleanup = base::ScopeGuard([&] {
+ // if any threads are started, shut them down
+ (void)shutdownAndWait(true);
+
+ mShutdownListener = nullptr;
+ mEventListener.clear();
+
+ mId.clear();
+
+ mShutdownTrigger = nullptr;
+ mRpcBinderState = std::make_unique<RpcState>();
+
+ // protocol version may have been downgraded - if we reuse this object
+ // to connect to another server, force that server to request a
+ // downgrade again
+ mProtocolVersion = oldProtocolVersion;
+
+ mConnections = {};
+ });
+
+ if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status;
+
+ {
+ ExclusiveConnection connection;
+ if (status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+ ConnectionUse::CLIENT, &connection);
+ status != OK)
+ return status;
+
+ uint32_t version;
+ if (status_t status =
+ state()->readNewSessionResponse(connection.get(),
+ sp<RpcSession>::fromExisting(this), &version);
+ status != OK)
+ return status;
+ if (!setProtocolVersion(version)) return BAD_VALUE;
+ }
+
+ // TODO(b/189955605): we should add additional sessions dynamically
// instead of all at once.
- // TODO(b/186470974): first risk of blocking
size_t numThreadsAvailable;
if (status_t status = getRemoteMaxThreads(&numThreadsAvailable); status != OK) {
- ALOGE("Could not get max threads after initial session to %s: %s", addr.toString().c_str(),
+ ALOGE("Could not get max threads after initial session setup: %s",
statusToString(status).c_str());
- return false;
+ return status;
}
if (status_t status = readId(); status != OK) {
- ALOGE("Could not get session id after initial session to %s; %s", addr.toString().c_str(),
+ ALOGE("Could not get session id after initial session setup: %s",
statusToString(status).c_str());
- return false;
+ return status;
}
+ size_t outgoingThreads = std::min(numThreadsAvailable, mMaxOutgoingThreads);
+ ALOGI_IF(outgoingThreads != numThreadsAvailable,
+ "Server hints client to start %zu outgoing threads, but client will only start %zu "
+ "because it is preconfigured to start at most %zu outgoing threads.",
+ numThreadsAvailable, outgoingThreads, mMaxOutgoingThreads);
+
+ // TODO(b/189955605): we should add additional sessions dynamically
+ // instead of all at once - the other side should be responsible for setting
+ // up additional connections. We need to create at least one (unless 0 are
+ // requested to be set) in order to allow the other side to reliably make
+ // any requests at all.
+
// we've already setup one client
- for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
- // TODO(b/185167543): shutdown existing connections?
- if (!setupOneSocketClient(addr, mId.value())) return false;
+ LOG_RPC_DETAIL("RpcSession::setupClient() instantiating %zu outgoing (server max: %zu) and %zu "
+ "incoming threads",
+ outgoingThreads, numThreadsAvailable, mMaxIncomingThreads);
+ for (size_t i = 0; i + 1 < outgoingThreads; i++) {
+ if (status_t status = connectAndInit(mId, false /*incoming*/); status != OK) return status;
}
- return true;
+ for (size_t i = 0; i < mMaxIncomingThreads; i++) {
+ if (status_t status = connectAndInit(mId, true /*incoming*/); status != OK) return status;
+ }
+
+ cleanup.Disable();
+
+ return OK;
}
-bool RpcSession::setupOneSocketClient(const RpcSocketAddress& addr, int32_t id) {
+status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+ return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) {
+ return setupOneSocketConnection(addr, sessionId, incoming);
+ });
+}
+
+status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
+ const std::vector<uint8_t>& sessionId,
+ bool incoming) {
for (size_t tries = 0; tries < 5; tries++) {
if (tries > 0) usleep(10000);
- unique_fd serverFd(
- TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ unique_fd serverFd(TEMP_FAILURE_RETRY(
+ socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
if (serverFd == -1) {
int savedErrno = errno;
ALOGE("Could not create socket at %s: %s", addr.toString().c_str(),
strerror(savedErrno));
- return false;
+ return -savedErrno;
}
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
- if (errno == ECONNRESET) {
+ int connErrno = errno;
+ if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
+ // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
+ // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
+ status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+ if (pollStatus != OK) {
+ ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
+ statusToString(pollStatus).c_str());
+ return pollStatus;
+ }
+ // Set connErrno to the errno that connect() would have set if the fd were blocking.
+ socklen_t connErrnoLen = sizeof(connErrno);
+ int ret =
+ getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &connErrno, &connErrnoLen);
+ if (ret == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s. "
+ "(Original error from connect() is: %s)",
+ strerror(savedErrno), strerror(connErrno));
+ return -savedErrno;
+ }
+ // Retrieved the real connErrno as if connect() was called with a blocking socket
+ // fd. Continue checking connErrno.
+ }
+ if (connErrno == ECONNRESET) {
ALOGW("Connection reset on %s", addr.toString().c_str());
continue;
}
- int savedErrno = errno;
- ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
- strerror(savedErrno));
- return false;
+ // connErrno could be zero if getsockopt determines so. Hence zero-check again.
+ if (connErrno != 0) {
+ ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
+ strerror(connErrno));
+ return -connErrno;
+ }
}
-
- if (sizeof(id) != TEMP_FAILURE_RETRY(write(serverFd.get(), &id, sizeof(id)))) {
- int savedErrno = errno;
- ALOGE("Could not write id to 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());
- addClientConnection(std::move(serverFd));
- return true;
+ return initAndAddConnection(std::move(serverFd), sessionId, incoming);
}
ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
- return false;
+ return UNKNOWN_ERROR;
}
-void RpcSession::addClientConnection(unique_fd fd) {
- std::lock_guard<std::mutex> _l(mMutex);
- sp<RpcConnection> session = sp<RpcConnection>::make();
- session->fd = std::move(fd);
- mClientConnections.push_back(session);
+status_t RpcSession::initAndAddConnection(unique_fd fd, const std::vector<uint8_t>& sessionId,
+ bool incoming) {
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
+ auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
+ if (server == nullptr) {
+ ALOGE("%s: Unable to set up RpcTransport", __PRETTY_FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+
+ LOG_RPC_DETAIL("Socket at client with RpcTransport %p", server.get());
+
+ if (sessionId.size() > std::numeric_limits<uint16_t>::max()) {
+ ALOGE("Session ID too big %zu", sessionId.size());
+ return BAD_VALUE;
+ }
+
+ RpcConnectionHeader header{
+ .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
+ .options = 0,
+ .sessionIdSize = static_cast<uint16_t>(sessionId.size()),
+ };
+
+ if (incoming) {
+ header.options |= RPC_CONNECTION_OPTION_INCOMING;
+ }
+
+ iovec headerIov{&header, sizeof(header)};
+ auto sendHeaderStatus =
+ server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1, {});
+ if (sendHeaderStatus != OK) {
+ ALOGE("Could not write connection header to socket: %s",
+ statusToString(sendHeaderStatus).c_str());
+ return sendHeaderStatus;
+ }
+
+ if (sessionId.size() > 0) {
+ iovec sessionIov{const_cast<void*>(static_cast<const void*>(sessionId.data())),
+ sessionId.size()};
+ auto sendSessionIdStatus =
+ server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1, {});
+ if (sendSessionIdStatus != OK) {
+ ALOGE("Could not write session ID ('%s') to socket: %s",
+ base::HexString(sessionId.data(), sessionId.size()).c_str(),
+ statusToString(sendSessionIdStatus).c_str());
+ return sendSessionIdStatus;
+ }
+ }
+
+ LOG_RPC_DETAIL("Socket at client: header sent");
+
+ if (incoming) {
+ return addIncomingConnection(std::move(server));
+ } else {
+ return addOutgoingConnection(std::move(server), true /*init*/);
+ }
}
-void RpcSession::setForServer(const wp<RpcServer>& server, int32_t sessionId) {
+status_t RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
+ std::mutex mutex;
+ std::condition_variable joinCv;
+ std::unique_lock<std::mutex> lock(mutex);
+ std::thread thread;
+ sp<RpcSession> thiz = sp<RpcSession>::fromExisting(this);
+ bool ownershipTransferred = false;
+ thread = std::thread([&]() {
+ std::unique_lock<std::mutex> threadLock(mutex);
+ std::unique_ptr<RpcTransport> movedRpcTransport = std::move(rpcTransport);
+ // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
+ sp<RpcSession> session = thiz;
+ session->preJoinThreadOwnership(std::move(thread));
+
+ // only continue once we have a response or the connection fails
+ auto setupResult = session->preJoinSetup(std::move(movedRpcTransport));
+
+ ownershipTransferred = true;
+ threadLock.unlock();
+ joinCv.notify_one();
+ // do not use & vars below
+
+ RpcSession::join(std::move(session), std::move(setupResult));
+ });
+ joinCv.wait(lock, [&] { return ownershipTransferred; });
+ LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
+ return OK;
+}
+
+status_t RpcSession::initShutdownTrigger() {
+ // first client connection added, but setForServer not called, so
+ // initializaing for a client.
+ if (mShutdownTrigger == nullptr) {
+ mShutdownTrigger = FdTrigger::make();
+ mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
+ if (mShutdownTrigger == nullptr) return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
+ sp<RpcConnection> connection = sp<RpcConnection>::make();
+ {
+ std::lock_guard<std::mutex> _l(mMutex);
+ connection->rpcTransport = std::move(rpcTransport);
+ connection->exclusiveTid = gettid();
+ mConnections.mOutgoing.push_back(connection);
+ }
+
+ status_t status = OK;
+ if (init) {
+ status =
+ mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+ }
+
+ {
+ std::lock_guard<std::mutex> _l(mMutex);
+ connection->exclusiveTid = std::nullopt;
+ }
+
+ return status;
+}
+
+bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
+ const std::vector<uint8_t>& sessionId,
+ const sp<IBinder>& sessionSpecificRoot) {
+ LOG_ALWAYS_FATAL_IF(mForServer != nullptr);
+ LOG_ALWAYS_FATAL_IF(server == nullptr);
+ LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
+ LOG_ALWAYS_FATAL_IF(eventListener == nullptr);
+ LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr);
+
+ mShutdownTrigger = FdTrigger::make();
+ if (mShutdownTrigger == nullptr) return false;
+
mId = sessionId;
mForServer = server;
+ mEventListener = eventListener;
+ mSessionSpecificRootObject = sessionSpecificRoot;
+ return true;
}
-sp<RpcSession::RpcConnection> RpcSession::assignServerToThisThread(unique_fd fd) {
+sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
+ std::unique_ptr<RpcTransport> rpcTransport) {
std::lock_guard<std::mutex> _l(mMutex);
+
+ if (mConnections.mIncoming.size() >= mMaxIncomingThreads) {
+ ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
+ mConnections.mIncoming.size(), mMaxIncomingThreads);
+ return nullptr;
+ }
+
+ // Don't accept any more connections, some have shutdown. Usually this
+ // happens when new connections are still being established as part of a
+ // very short-lived session which shuts down after it already started
+ // accepting new connections.
+ if (mConnections.mIncoming.size() < mConnections.mMaxIncoming) {
+ return nullptr;
+ }
+
sp<RpcConnection> session = sp<RpcConnection>::make();
- session->fd = std::move(fd);
+ session->rpcTransport = std::move(rpcTransport);
session->exclusiveTid = gettid();
- mServerConnections.push_back(session);
+
+ mConnections.mIncoming.push_back(session);
+ mConnections.mMaxIncoming = mConnections.mIncoming.size();
return session;
}
-bool RpcSession::removeServerConnection(const sp<RpcConnection>& connection) {
- std::lock_guard<std::mutex> _l(mMutex);
- if (auto it = std::find(mServerConnections.begin(), mServerConnections.end(), connection);
- it != mServerConnections.end()) {
- mServerConnections.erase(it);
- if (mServerConnections.size() == 0) {
- terminateLocked();
+bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
+ std::unique_lock<std::mutex> _l(mMutex);
+ if (auto it =
+ std::find(mConnections.mIncoming.begin(), mConnections.mIncoming.end(), connection);
+ it != mConnections.mIncoming.end()) {
+ mConnections.mIncoming.erase(it);
+ if (mConnections.mIncoming.size() == 0) {
+ sp<EventListener> listener = mEventListener.promote();
+ if (listener) {
+ _l.unlock();
+ listener->onSessionAllIncomingThreadsEnded(sp<RpcSession>::fromExisting(this));
+ }
}
return true;
}
return false;
}
-RpcSession::ExclusiveConnection::ExclusiveConnection(const sp<RpcSession>& session,
- ConnectionUse use)
- : mSession(session) {
- pid_t tid = gettid();
- std::unique_lock<std::mutex> _l(mSession->mMutex);
+std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
+ return mCtx->getCertificate(format);
+}
- mSession->mWaitingThreads++;
+status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, ConnectionUse use,
+ ExclusiveConnection* connection) {
+ connection->mSession = session;
+ connection->mConnection = nullptr;
+ connection->mReentrant = false;
+
+ pid_t tid = gettid();
+ std::unique_lock<std::mutex> _l(session->mMutex);
+
+ session->mConnections.mWaitingThreads++;
while (true) {
sp<RpcConnection> exclusive;
sp<RpcConnection> available;
// CHECK FOR DEDICATED CLIENT SOCKET
//
- // A server/looper should always use a dedicated session if available
- findConnection(tid, &exclusive, &available, mSession->mClientConnections,
- mSession->mClientConnectionsOffset);
+ // A server/looper should always use a dedicated connection if available
+ findConnection(tid, &exclusive, &available, session->mConnections.mOutgoing,
+ session->mConnections.mOutgoingOffset);
// WARNING: this assumes a server cannot request its client to send
- // a transaction, as mServerConnections is excluded below.
+ // a transaction, as mIncoming 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
@@ -326,41 +814,66 @@
// command. So, we move to considering the second available thread
// for subsequent calls.
if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
- mSession->mClientConnectionsOffset =
- (mSession->mClientConnectionsOffset + 1) % mSession->mClientConnections.size();
+ session->mConnections.mOutgoingOffset = (session->mConnections.mOutgoingOffset + 1) %
+ session->mConnections.mOutgoing.size();
}
- // USE SERVING SOCKET (for nested transaction)
- //
- // asynchronous calls cannot be nested
+ // USE SERVING SOCKET (e.g. nested transaction)
if (use != ConnectionUse::CLIENT_ASYNC) {
+ sp<RpcConnection> exclusiveIncoming;
// server connections are always assigned to a thread
- findConnection(tid, &exclusive, nullptr /*available*/, mSession->mServerConnections,
- 0 /* index hint */);
+ findConnection(tid, &exclusiveIncoming, nullptr /*available*/,
+ session->mConnections.mIncoming, 0 /* index hint */);
+
+ // asynchronous calls cannot be nested, we currently allow ref count
+ // calls to be nested (so that you can use this without having extra
+ // threads). Note 'drainCommands' is used so that these ref counts can't
+ // build up.
+ if (exclusiveIncoming != nullptr) {
+ if (exclusiveIncoming->allowNested) {
+ // guaranteed to be processed as nested command
+ exclusive = exclusiveIncoming;
+ } else if (use == ConnectionUse::CLIENT_REFCOUNT && available == nullptr) {
+ // prefer available socket, but if we don't have one, don't
+ // wait for one
+ exclusive = exclusiveIncoming;
+ }
+ }
}
- // if our thread is already using a session, prioritize using that
+ // if our thread is already using a connection, prioritize using that
if (exclusive != nullptr) {
- mConnection = exclusive;
- mReentrant = true;
+ connection->mConnection = exclusive;
+ connection->mReentrant = true;
break;
} else if (available != nullptr) {
- mConnection = available;
- mConnection->exclusiveTid = tid;
+ connection->mConnection = available;
+ connection->mConnection->exclusiveTid = tid;
break;
}
- // in regular binder, this would usually be a deadlock :)
- LOG_ALWAYS_FATAL_IF(mSession->mClientConnections.size() == 0,
- "Not a client of any session. You must create a session to an "
- "RPC server to make any non-nested (e.g. oneway or on another thread) "
- "calls.");
+ if (session->mConnections.mOutgoing.size() == 0) {
+ ALOGE("Session has no outgoing connections. This is required for an RPC server to make "
+ "any non-nested (e.g. oneway or on another thread) calls. Use code request "
+ "reason: %d. Incoming connections: %zu. %s.",
+ static_cast<int>(use), session->mConnections.mIncoming.size(),
+ (session->server()
+ ? "This is a server session, so see RpcSession::setMaxIncomingThreads "
+ "for the corresponding client"
+ : "This is a client session, so see RpcSession::setMaxOutgoingThreads "
+ "for this client or RpcServer::setMaxThreads for the corresponding "
+ "server"));
+ return WOULD_BLOCK;
+ }
- LOG_RPC_DETAIL("No available session (have %zu clients and %zu servers). Waiting...",
- mSession->mClientConnections.size(), mSession->mServerConnections.size());
- mSession->mAvailableConnectionCv.wait(_l);
+ LOG_RPC_DETAIL("No available connections (have %zu clients and %zu servers). Waiting...",
+ session->mConnections.mOutgoing.size(),
+ session->mConnections.mIncoming.size());
+ session->mAvailableConnectionCv.wait(_l);
}
- mSession->mWaitingThreads--;
+ session->mConnections.mWaitingThreads--;
+
+ return OK;
}
void RpcSession::ExclusiveConnection::findConnection(pid_t tid, sp<RpcConnection>* exclusive,
@@ -375,13 +888,13 @@
for (size_t i = 0; i < sockets.size(); i++) {
sp<RpcConnection>& socket = sockets[(i + socketsIndexHint) % sockets.size()];
- // take first available session (intuition = caching)
+ // take first available connection (intuition = caching)
if (available && *available == nullptr && socket->exclusiveTid == std::nullopt) {
*available = socket;
continue;
}
- // though, prefer to take session which is already inuse by this thread
+ // though, prefer to take connection which is already inuse by this thread
// (nested transactions)
if (exclusive && socket->exclusiveTid == tid) {
*exclusive = socket;
@@ -391,13 +904,13 @@
}
RpcSession::ExclusiveConnection::~ExclusiveConnection() {
- // reentrant use of a session means something less deep in the call stack
+ // 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) {
+ if (!mReentrant && mConnection != nullptr) {
std::unique_lock<std::mutex> _l(mSession->mMutex);
mConnection->exclusiveTid = std::nullopt;
- if (mSession->mWaitingThreads > 0) {
+ if (mSession->mConnections.mWaitingThreads > 0) {
_l.unlock();
mSession->mAvailableConnectionCv.notify_one();
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 2ba9fa2..6d89064 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -18,25 +18,46 @@
#include "RpcState.h"
+#include <android-base/hex.h>
+#include <android-base/macros.h>
+#include <android-base/scopeguard.h>
#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
#include <binder/RpcServer.h>
#include "Debug.h"
#include "RpcWireFormat.h"
+#include <random>
+
#include <inttypes.h>
namespace android {
+using base::ScopeGuard;
+
+#if RPC_FLAKE_PRONE
+void rpcMaybeWaitToFlake() {
+ [[clang::no_destroy]] static std::random_device r;
+ [[clang::no_destroy]] static std::mutex m;
+ unsigned num;
+ {
+ std::lock_guard<std::mutex> lock(m);
+ num = r();
+ }
+ if (num % 10 == 0) usleep(num % 1000);
+}
+#endif
+
RpcState::RpcState() {}
RpcState::~RpcState() {}
status_t RpcState::onBinderLeaving(const sp<RpcSession>& session, const sp<IBinder>& binder,
- RpcAddress* outAddress) {
+ uint64_t* outAddress) {
bool isRemote = binder->remoteBinder();
bool isRpc = isRemote && binder->remoteBinder()->isRpcBinder();
- if (isRpc && binder->remoteBinder()->getPrivateAccessorForId().rpcSession() != session) {
+ if (isRpc && binder->remoteBinder()->getPrivateAccessor().rpcSession() != session) {
// 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.
@@ -57,18 +78,17 @@
}
std::lock_guard<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT;
// 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");
+ // check integrity of data structure
+ uint64_t actualAddr = binder->remoteBinder()->getPrivateAccessor().rpcAddress();
+ LOG_ALWAYS_FATAL_IF(addr != actualAddr, "Address mismatch %" PRIu64 " vs %" PRIu64,
+ addr, actualAddr);
}
node.timesSent++;
node.sentRef = binder; // might already be set
@@ -78,36 +98,78 @@
}
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);
+ bool forServer = session->server() != nullptr;
- *outAddress = it->first;
- return OK;
+ // arbitrary limit for maximum number of nodes in a process (otherwise we
+ // might run out of addresses)
+ if (mNodeForAddress.size() > 100000) {
+ return NO_MEMORY;
+ }
+
+ while (true) {
+ RpcWireAddress address{
+ .options = RPC_WIRE_ADDRESS_OPTION_CREATED,
+ .address = mNextId,
+ };
+ if (forServer) {
+ address.options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
+ }
+
+ // avoid ubsan abort
+ if (mNextId >= std::numeric_limits<uint32_t>::max()) {
+ mNextId = 0;
+ } else {
+ mNextId++;
+ }
+
+ auto&& [it, inserted] = mNodeForAddress.insert({RpcWireAddress::toRaw(address),
+ BinderNode{
+ .binder = binder,
+ .sentRef = binder,
+ .timesSent = 1,
+ }});
+ if (inserted) {
+ *outAddress = it->first;
+ return OK;
+ }
+ }
}
-sp<IBinder> RpcState::onBinderEntering(const sp<RpcSession>& session, const RpcAddress& address) {
- std::unique_lock<std::mutex> _l(mNodeMutex);
+status_t RpcState::onBinderEntering(const sp<RpcSession>& session, uint64_t address,
+ sp<IBinder>* out) {
+ // ensure that: if we want to use addresses for something else in the future (for
+ // instance, allowing transitive binder sends), that we don't accidentally
+ // send those addresses to old server. Accidentally ignoring this in that
+ // case and considering the binder to be recognized could cause this
+ // process to accidentally proxy transactions for that binder. Of course,
+ // if we communicate with a binder, it could always be proxying
+ // information. However, we want to make sure that isn't done on accident
+ // by a client.
+ RpcWireAddress addr = RpcWireAddress::fromRaw(address);
+ constexpr uint32_t kKnownOptions =
+ RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
+ if (addr.options & ~kKnownOptions) {
+ ALOGE("Address is of an unknown type, rejecting: %" PRIu64, address);
+ return BAD_VALUE;
+ }
+
+ std::lock_guard<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT;
if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
- sp<IBinder> binder = it->second.binder.promote();
+ *out = it->second.binder.promote();
// implicitly have strong RPC refcount, since we received this binder
it->second.timesRecd++;
+ return OK;
+ }
- _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)session->sendDecStrong(address);
-
- return binder;
+ // we don't know about this binder, so the other side of the connection
+ // should have created it.
+ if ((addr.options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER) == !!session->server()) {
+ ALOGE("Server received unrecognized address which we should own the creation of %" PRIu64,
+ address);
+ return BAD_VALUE;
}
auto&& [it, inserted] = mNodeForAddress.insert({address, BinderNode{}});
@@ -115,10 +177,42 @@
// Currently, all binders are assumed to be part of the same session (no
// device global binders in the RPC world).
- sp<IBinder> binder = BpBinder::create(session, it->first);
- it->second.binder = binder;
+ it->second.binder = *out = BpBinder::PrivateAccessor::create(session, it->first);
it->second.timesRecd = 1;
- return binder;
+ return OK;
+}
+
+status_t RpcState::flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+ const sp<IBinder>& binder) {
+ // We can flush all references when the binder is destroyed. No need to send
+ // extra reference counting packets now.
+ if (binder->remoteBinder()) return OK;
+
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT;
+
+ auto it = mNodeForAddress.find(address);
+
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Can't be deleted while we hold sp<>");
+ LOG_ALWAYS_FATAL_IF(it->second.binder != binder,
+ "Caller of flushExcessBinderRefs using inconsistent arguments");
+
+ LOG_ALWAYS_FATAL_IF(it->second.timesSent <= 0, "Local binder must have been sent %p",
+ binder.get());
+
+ // For a local binder, we only need to know that we sent it. Now that we
+ // have an sp<> for this call, we don't need anything more. If the other
+ // process is done with this binder, it needs to know we received the
+ // refcount associated with this call, so we can acknowledge that we
+ // received it. Once (or if) it has no other refcounts, it would reply with
+ // its own decStrong so that it could be removed from this session.
+ if (it->second.timesRecd != 0) {
+ _l.unlock();
+
+ return session->sendDecStrongToTarget(address, 0);
+ }
+
+ return OK;
}
size_t RpcState::countBinders() {
@@ -128,6 +222,45 @@
void RpcState::dump() {
std::lock_guard<std::mutex> _l(mNodeMutex);
+ dumpLocked();
+}
+
+void RpcState::clear() {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+
+ if (mTerminated) {
+ LOG_ALWAYS_FATAL_IF(!mNodeForAddress.empty(),
+ "New state should be impossible after terminating!");
+ return;
+ }
+
+ if (SHOULD_LOG_RPC_DETAIL) {
+ ALOGE("RpcState::clear()");
+ dumpLocked();
+ }
+
+ // 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;
+
+ 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();
+
+ _l.unlock();
+ tempHoldBinder.clear(); // explicit
+}
+
+void RpcState::dumpLocked() {
ALOGE("DUMP OF RpcState %p", this);
ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size());
for (const auto& [address, node] : mNodeForAddress) {
@@ -148,39 +281,12 @@
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("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s",
+ node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, 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();
- }
-}
RpcState::CommandData::CommandData(size_t size) : mSize(size) {
// The maximum size for regular binder is 1MB for all concurrent
@@ -203,62 +309,93 @@
mData.reset(new (std::nothrow) uint8_t[size]);
}
-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;
+status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) {
+ for (int i = 0; i < niovs; i++) {
+ LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s",
+ what, i + 1, niovs, connection->rpcTransport.get(),
+ android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
- 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;
+ if (status_t status =
+ connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
+ iovs, niovs, altPoll);
+ status != OK) {
+ LOG_RPC_DETAIL("Failed to write %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
+ connection->rpcTransport.get(), statusToString(status).c_str());
+ (void)session->shutdownAndWait(false);
+ return status;
}
- return true;
+ return OK;
}
-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;
+status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const char* what, iovec* iovs, int niovs) {
+ if (status_t status =
+ connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
+ iovs, niovs, {});
+ status != OK) {
+ LOG_RPC_DETAIL("Failed to read %s (%d iovs) on RpcTransport %p, error: %s", what, niovs,
+ connection->rpcTransport.get(), statusToString(status).c_str());
+ (void)session->shutdownAndWait(false);
+ return status;
}
- 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());
+ for (int i = 0; i < niovs; i++) {
+ LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s",
+ what, i + 1, niovs, connection->rpcTransport.get(),
+ android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
-
- return true;
+ return OK;
}
-sp<IBinder> RpcState::getRootObject(const base::unique_fd& fd, const sp<RpcSession>& session) {
+status_t RpcState::readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint32_t* version) {
+ RpcNewSessionResponse response;
+ iovec iov{&response, sizeof(response)};
+ if (status_t status = rpcRec(connection, session, "new session response", &iov, 1);
+ status != OK) {
+ return status;
+ }
+ *version = response.version;
+ return OK;
+}
+
+status_t RpcState::sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session) {
+ RpcOutgoingConnectionInit init{
+ .msg = RPC_CONNECTION_INIT_OKAY,
+ };
+ iovec iov{&init, sizeof(init)};
+ return rpcSend(connection, session, "connection init", &iov, 1);
+}
+
+status_t RpcState::readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session) {
+ RpcOutgoingConnectionInit init;
+ iovec iov{&init, sizeof(init)};
+ if (status_t status = rpcRec(connection, session, "connection init", &iov, 1); status != OK)
+ return status;
+
+ static_assert(sizeof(init.msg) == sizeof(RPC_CONNECTION_INIT_OKAY));
+ if (0 != strncmp(init.msg, RPC_CONNECTION_INIT_OKAY, sizeof(init.msg))) {
+ ALOGE("Connection init message unrecognized %.*s", static_cast<int>(sizeof(init.msg)),
+ init.msg);
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+sp<IBinder> RpcState::getRootObject(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session) {
Parcel data;
data.markForRpc(session);
Parcel reply;
- status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT, data, session,
- &reply, 0);
+ status_t status =
+ transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_ROOT, data, session, &reply, 0);
if (status != OK) {
ALOGE("Error getting root object: %s", statusToString(status).c_str());
return nullptr;
@@ -267,14 +404,14 @@
return reply.readStrongBinder();
}
-status_t RpcState::getMaxThreads(const base::unique_fd& fd, const sp<RpcSession>& session,
- size_t* maxThreadsOut) {
+status_t RpcState::getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, size_t* maxThreadsOut) {
Parcel data;
data.markForRpc(session);
Parcel reply;
- status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data,
- session, &reply, 0);
+ status_t status = transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data,
+ session, &reply, 0);
if (status != OK) {
ALOGE("Error getting max threads: %s", statusToString(status).c_str());
return status;
@@ -292,93 +429,135 @@
return OK;
}
-status_t RpcState::getSessionId(const base::unique_fd& fd, const sp<RpcSession>& session,
- int32_t* sessionIdOut) {
+status_t RpcState::getSessionId(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut) {
Parcel data;
data.markForRpc(session);
Parcel reply;
- status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_SESSION_ID, data,
- session, &reply, 0);
+ status_t status = transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_SESSION_ID, data,
+ session, &reply, 0);
if (status != OK) {
ALOGE("Error getting session ID: %s", statusToString(status).c_str());
return status;
}
- int32_t sessionId;
- status = reply.readInt32(&sessionId);
- if (status != OK) return status;
-
- *sessionIdOut = sessionId;
- return OK;
+ return reply.readByteVector(sessionIdOut);
}
-status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address, uint32_t code,
- const Parcel& data, const sp<RpcSession>& session, 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++;
- }
- }
-
+status_t RpcState::transact(const sp<RpcSession::RpcConnection>& connection,
+ const sp<IBinder>& binder, uint32_t code, const Parcel& data,
+ const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
if (!data.isForRpc()) {
- ALOGE("Refusing to send RPC with parcel not crafted for RPC");
+ ALOGE("Refusing to send RPC with parcel not crafted for RPC call on binder %p code "
+ "%" PRIu32,
+ binder.get(), code);
return BAD_TYPE;
}
if (data.objectsCount() != 0) {
- ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data);
+ ALOGE("Parcel at %p has attached objects but is being used in an RPC call on binder %p "
+ "code %" PRIu32,
+ &data, binder.get(), code);
return BAD_TYPE;
}
+ uint64_t address;
+ if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status;
+
+ return transactAddress(connection, address, code, data, session, reply, flags);
+}
+
+status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connection,
+ uint64_t address, uint32_t code, const Parcel& data,
+ const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
+ LOG_ALWAYS_FATAL_IF(!data.isForRpc());
+ LOG_ALWAYS_FATAL_IF(data.objectsCount() != 0);
+
+ uint64_t asyncNumber = 0;
+
+ if (address != 0) {
+ std::unique_lock<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 %" PRIu64, address);
+
+ if (flags & IBinder::FLAG_ONEWAY) {
+ asyncNumber = it->second.asyncNumber;
+ if (!nodeProgressAsyncNumber(&it->second)) {
+ _l.unlock();
+ (void)session->shutdownAndWait(false);
+ return DEAD_OBJECT;
+ }
+ }
+ }
+
+ LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
+ sizeof(RpcWireTransaction) <
+ data.dataSize(),
+ "Too much data %zu", data.dataSize());
+
+ RpcWireHeader command{
+ .command = RPC_COMMAND_TRANSACT,
+ .bodySize = static_cast<uint32_t>(sizeof(RpcWireTransaction) + data.dataSize()),
+ };
+
RpcWireTransaction transaction{
- .address = address.viewRawEmbedded(),
+ .address = RpcWireAddress::fromRaw(address),
.code = code,
.flags = flags,
.asyncNumber = asyncNumber,
};
- CommandData transactionData(sizeof(RpcWireTransaction) + data.dataSize());
- if (!transactionData.valid()) {
- return NO_MEMORY;
- }
+ constexpr size_t kWaitMaxUs = 1000000;
+ constexpr size_t kWaitLogUs = 10000;
+ size_t waitUs = 0;
- memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction));
- memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize());
+ // Oneway calls have no sync point, so if many are sent before, whether this
+ // is a twoway or oneway transaction, they may have filled up the socket.
+ // So, make sure we drain them before polling.
+ std::function<status_t()> drainRefs = [&] {
+ if (waitUs > kWaitLogUs) {
+ ALOGE("Cannot send command, trying to process pending refcounts. Waiting %zuus. Too "
+ "many oneway calls?",
+ waitUs);
+ }
- if (transactionData.size() > std::numeric_limits<uint32_t>::max()) {
- ALOGE("Transaction size too big %zu", transactionData.size());
- return BAD_VALUE;
- }
+ if (waitUs > 0) {
+ usleep(waitUs);
+ waitUs = std::min(kWaitMaxUs, waitUs * 2);
+ } else {
+ waitUs = 1;
+ }
- RpcWireHeader command{
- .command = RPC_COMMAND_TRANSACT,
- .bodySize = static_cast<uint32_t>(transactionData.size()),
+ return drainCommands(connection, session, CommandType::CONTROL_ONLY);
};
- if (!rpcSend(fd, "transact header", &command, sizeof(command))) {
- return DEAD_OBJECT;
- }
- if (!rpcSend(fd, "command body", transactionData.data(), transactionData.size())) {
- return DEAD_OBJECT;
+ iovec iovs[]{
+ {&command, sizeof(RpcWireHeader)},
+ {&transaction, sizeof(RpcWireTransaction)},
+ {const_cast<uint8_t*>(data.data()), data.dataSize()},
+ };
+ if (status_t status =
+ rpcSend(connection, session, "transaction", iovs, arraysize(iovs), drainRefs);
+ status != OK) {
+ // TODO(b/167966510): need to undo onBinderLeaving - we know the
+ // refcount isn't successfully transferred.
+ return status;
}
if (flags & IBinder::FLAG_ONEWAY) {
- return OK; // do not wait for result
+ LOG_RPC_DETAIL("Oneway command, so no longer waiting on RpcTransport %p",
+ connection->rpcTransport.get());
+
+ // Do not wait on result.
+ return OK;
}
LOG_ALWAYS_FATAL_IF(reply == nullptr, "Reply parcel must be used for synchronous transaction.");
- return waitForReply(fd, session, reply);
+ return waitForReply(connection, session, reply);
}
static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
@@ -387,36 +566,36 @@
delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
(void)dataSize;
LOG_ALWAYS_FATAL_IF(objects != nullptr);
- LOG_ALWAYS_FATAL_IF(objectsCount, 0);
+ LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
}
-status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcSession>& session,
- Parcel* reply) {
+status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, Parcel* reply) {
RpcWireHeader command;
while (true) {
- if (!rpcRec(fd, "command header", &command, sizeof(command))) {
- return DEAD_OBJECT;
- }
+ iovec iov{&command, sizeof(command)};
+ if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1);
+ status != OK)
+ return status;
if (command.command == RPC_COMMAND_REPLY) break;
- status_t status = processServerCommand(fd, session, command);
- if (status != OK) return status;
+ if (status_t status = processCommand(connection, session, command, CommandType::ANY);
+ status != OK)
+ return status;
}
CommandData data(command.bodySize);
- if (!data.valid()) {
- return NO_MEMORY;
- }
+ if (!data.valid()) return NO_MEMORY;
- if (!rpcRec(fd, "reply body", data.data(), command.bodySize)) {
- return DEAD_OBJECT;
- }
+ iovec iov{data.data(), command.bodySize};
+ if (status_t status = rpcRec(connection, session, "reply body", &iov, 1); status != OK)
+ return status;
if (command.bodySize < sizeof(RpcWireReply)) {
ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
sizeof(RpcWireReply), command.bodySize);
- terminate();
+ (void)session->shutdownAndWait(false);
return BAD_VALUE;
}
RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
@@ -431,50 +610,95 @@
return OK;
}
-status_t RpcState::sendDecStrong(const base::unique_fd& fd, const RpcAddress& addr) {
+status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint64_t addr,
+ size_t target) {
+ RpcDecStrong body = {
+ .address = RpcWireAddress::fromRaw(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());
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
+ "Sending dec strong on unknown address %" PRIu64, addr);
- it->second.timesRecd--;
- if (it->second.timesRecd == 0 && it->second.timesSent == 0) {
- mNodeForAddress.erase(it);
- }
+ LOG_ALWAYS_FATAL_IF(it->second.timesRecd < target, "Can't dec count of %zu to %zu.",
+ it->second.timesRecd, target);
+
+ // typically this happens when multiple threads send dec refs at the
+ // same time - the transactions will get combined automatically
+ if (it->second.timesRecd == target) return OK;
+
+ body.amount = it->second.timesRecd - target;
+ it->second.timesRecd = target;
+
+ LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
+ "Bad state. RpcState shouldn't own received binder");
}
RpcWireHeader cmd = {
.command = RPC_COMMAND_DEC_STRONG,
- .bodySize = sizeof(RpcWireAddress),
+ .bodySize = sizeof(RpcDecStrong),
};
- 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;
+ iovec iovs[]{{&cmd, sizeof(cmd)}, {&body, sizeof(body)}};
+ return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs));
+}
+
+status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, CommandType type) {
+ LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
+
+ RpcWireHeader command;
+ iovec iov{&command, sizeof(command)};
+ if (status_t status = rpcRec(connection, session, "command header (for server)", &iov, 1);
+ status != OK)
+ return status;
+
+ return processCommand(connection, session, command, type);
+}
+
+status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, CommandType type) {
+ uint8_t buf;
+ while (true) {
+ size_t num_bytes;
+ status_t status = connection->rpcTransport->peek(&buf, sizeof(buf), &num_bytes);
+ if (status == WOULD_BLOCK) break;
+ if (status != OK) return status;
+ if (!num_bytes) break;
+
+ status = getAndExecuteCommand(connection, session, type);
+ if (status != OK) return status;
+ }
return OK;
}
-status_t RpcState::getAndExecuteCommand(const base::unique_fd& fd, const sp<RpcSession>& session) {
- LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", fd.get());
-
- RpcWireHeader command;
- if (!rpcRec(fd, "command header", &command, sizeof(command))) {
- return DEAD_OBJECT;
+status_t RpcState::processCommand(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const RpcWireHeader& command,
+ CommandType type) {
+ IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull();
+ IPCThreadState::SpGuard spGuard{
+ .address = __builtin_frame_address(0),
+ .context = "processing binder RPC command",
+ };
+ const IPCThreadState::SpGuard* origGuard;
+ if (kernelBinderState != nullptr) {
+ origGuard = kernelBinderState->pushGetCallingSpGuard(&spGuard);
}
+ ScopeGuard guardUnguard = [&]() {
+ if (kernelBinderState != nullptr) {
+ kernelBinderState->restoreGetCallingSpGuard(origGuard);
+ }
+ };
- return processServerCommand(fd, session, command);
-}
-
-status_t RpcState::processServerCommand(const base::unique_fd& fd, const sp<RpcSession>& session,
- const RpcWireHeader& command) {
switch (command.command) {
case RPC_COMMAND_TRANSACT:
- return processTransact(fd, session, command);
+ if (type != CommandType::ANY) return BAD_TYPE;
+ return processTransact(connection, session, command);
case RPC_COMMAND_DEC_STRONG:
- return processDecStrong(fd, command);
+ return processDecStrong(connection, session, command);
}
// We should always know the version of the opposing side, and since the
@@ -483,22 +707,22 @@
// also can't consider it a fatal error because this would allow any client
// to kill us, so ending the session for misbehaving client.
ALOGE("Unknown RPC command %d - terminating session", command.command);
- terminate();
+ (void)session->shutdownAndWait(false);
return DEAD_OBJECT;
}
-status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcSession>& session,
- const RpcWireHeader& command) {
+status_t RpcState::processTransact(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
CommandData transactionData(command.bodySize);
if (!transactionData.valid()) {
return NO_MEMORY;
}
- if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) {
- return DEAD_OBJECT;
- }
+ iovec iov{transactionData.data(), transactionData.size()};
+ if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1); status != OK)
+ return status;
- return processTransactInternal(fd, session, std::move(transactionData));
+ return processTransactInternal(connection, session, std::move(transactionData));
}
static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize,
@@ -510,62 +734,88 @@
(void)objectsCount;
}
-status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session,
+status_t RpcState::processTransactInternal(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session,
CommandData transactionData) {
+ // for 'recursive' calls to this, we have already read and processed the
+ // binder from the transaction data and taken reference counts into account,
+ // so it is cached here.
+ sp<IBinder> target;
+processTransactInternalTailCall:
+
if (transactionData.size() < sizeof(RpcWireTransaction)) {
ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
sizeof(RpcWireTransaction), transactionData.size());
- terminate();
+ (void)session->shutdownAndWait(false);
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);
+ uint64_t addr = RpcWireAddress::toRaw(transaction->address);
+ bool oneway = transaction->flags & IBinder::FLAG_ONEWAY;
status_t replyStatus = OK;
- sp<IBinder> target;
- if (!addr.isZero()) {
- std::lock_guard<std::mutex> _l(mNodeMutex);
+ if (addr != 0) {
+ if (!target) {
+ replyStatus = onBinderEntering(session, addr, &target);
+ }
- auto it = mNodeForAddress.find(addr);
- if (it == mNodeForAddress.end()) {
- ALOGE("Unknown binder address %s.", addr.toString().c_str());
+ if (replyStatus != OK) {
+ // do nothing
+ } else 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
+ // session.
+ ALOGE("While transacting, binder has been deleted at address %" PRIu64 ". Terminating!",
+ addr);
+ (void)session->shutdownAndWait(false);
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
- // session.
- ALOGE("While transacting, binder has been deleted at address %s. Terminating!",
- addr.toString().c_str());
- terminate();
+ } else if (target->localBinder() == nullptr) {
+ ALOGE("Unknown binder address or non-local binder, not address %" PRIu64
+ ". Terminating!",
+ addr);
+ (void)session->shutdownAndWait(false);
+ replyStatus = BAD_VALUE;
+ } else if (oneway) {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ auto it = mNodeForAddress.find(addr);
+ if (it->second.binder.promote() != target) {
+ ALOGE("Binder became invalid during transaction. Bad client? %" PRIu64, addr);
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;
+ } else if (transaction->asyncNumber != it->second.asyncNumber) {
+ // we need to process some other asynchronous transaction
+ // first
+ it->second.asyncTodo.push(BinderNode::AsyncTodo{
+ .ref = target,
+ .data = std::move(transactionData),
+ .asyncNumber = transaction->asyncNumber,
+ });
+
+ size_t numPending = it->second.asyncTodo.size();
+ LOG_RPC_DETAIL("Enqueuing %" PRIu64 " on %" PRIu64 " (%zu pending)",
+ transaction->asyncNumber, addr, numPending);
+
+ constexpr size_t kArbitraryOnewayCallTerminateLevel = 10000;
+ constexpr size_t kArbitraryOnewayCallWarnLevel = 1000;
+ constexpr size_t kArbitraryOnewayCallWarnPer = 1000;
+
+ if (numPending >= kArbitraryOnewayCallWarnLevel) {
+ if (numPending >= kArbitraryOnewayCallTerminateLevel) {
+ ALOGE("WARNING: %zu pending oneway transactions. Terminating!", numPending);
+ _l.unlock();
+ (void)session->shutdownAndWait(false);
+ return FAILED_TRANSACTION;
+ }
+
+ if (numPending % kArbitraryOnewayCallWarnPer == 0) {
+ ALOGW("Warning: many oneway transactions built up on %p (%zu)",
+ target.get(), numPending);
+ }
}
+ return OK;
}
}
}
@@ -585,49 +835,56 @@
data.markForRpc(session);
if (target) {
+ bool origAllowNested = connection->allowNested;
+ connection->allowNested = !oneway;
+
replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
+
+ connection->allowNested = origAllowNested;
} else {
LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
- sp<RpcServer> server = session->server().promote();
- if (server) {
- // special case for 'zero' address (special server commands)
- switch (transaction->code) {
- case RPC_SPECIAL_TRANSACT_GET_ROOT: {
- replyStatus = reply.writeStrongBinder(server->getRootObject());
- break;
- }
- case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
- replyStatus = reply.writeInt32(server->getMaxThreads());
- break;
- }
- case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
- // only sessions w/ services can be the source of a
- // session ID (so still guarded by non-null server)
- //
- // sessions associated with servers must have an ID
- // (hence abort)
- int32_t id = session->getPrivateAccessorForId().get().value();
- replyStatus = reply.writeInt32(id);
- break;
- }
- default: {
- replyStatus = UNKNOWN_TRANSACTION;
+ switch (transaction->code) {
+ case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
+ replyStatus = reply.writeInt32(session->getMaxIncomingThreads());
+ break;
+ }
+ case RPC_SPECIAL_TRANSACT_GET_SESSION_ID: {
+ // for client connections, this should always report the value
+ // originally returned from the server, so this is asserting
+ // that it exists
+ replyStatus = reply.writeByteVector(session->mId);
+ break;
+ }
+ default: {
+ sp<RpcServer> server = session->server();
+ if (server) {
+ switch (transaction->code) {
+ case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+ sp<IBinder> root = session->mSessionSpecificRootObject
+ ?: server->getRootObject();
+ replyStatus = reply.writeStrongBinder(root);
+ break;
+ }
+ default: {
+ replyStatus = UNKNOWN_TRANSACTION;
+ }
+ }
+ } else {
+ ALOGE("Special command sent, but no server object attached.");
}
}
- } else {
- ALOGE("Special command sent, but no server object attached.");
}
}
}
- if (transaction->flags & IBinder::FLAG_ONEWAY) {
+ if (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());
+ LOG_RPC_DETAIL("Processed async transaction %" PRIu64 " on %" PRIu64,
+ transaction->asyncNumber, addr);
// Check to see if there is another asynchronous transaction to process.
// This behavior differs from binder behavior, since in the binder
@@ -645,123 +902,151 @@
// 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 (!nodeProgressAsyncNumber(&it->second)) {
+ _l.unlock();
+ (void)session->shutdownAndWait(false);
+ return DEAD_OBJECT;
+ }
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());
+ LOG_RPC_DETAIL("Found next async transaction %" PRIu64 " on %" PRIu64,
+ it->second.asyncNumber, addr);
// justification for const_cast (consider avoiding priority_queue):
- // - AsyncTodo operator< doesn't depend on 'data' object
+ // - AsyncTodo operator< doesn't depend on 'data' or 'ref' objects
// - gotta go fast
- CommandData data = std::move(
- const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
+ auto& todo = const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top());
+
+ // reset up arguments
+ transactionData = std::move(todo.data);
+ LOG_ALWAYS_FATAL_IF(target != todo.ref,
+ "async list should be associated with a binder");
+
it->second.asyncTodo.pop();
- _l.unlock();
- return processTransactInternal(fd, session, std::move(data));
+ goto processTransactInternalTailCall;
}
}
+
+ // done processing all the async commands on this binder that we can, so
+ // write decstrongs on the binder
+ if (addr != 0 && replyStatus == OK) {
+ return flushExcessBinderRefs(session, addr, target);
+ }
+
return OK;
}
+ // Binder refs are flushed for oneway calls only after all calls which are
+ // built up are executed. Otherwise, they fill up the binder buffer.
+ if (addr != 0 && replyStatus == OK) {
+ replyStatus = flushExcessBinderRefs(session, addr, target);
+ }
+
+ LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
+ sizeof(RpcWireReply) <
+ reply.dataSize(),
+ "Too much data for reply %zu", reply.dataSize());
+
+ RpcWireHeader cmdReply{
+ .command = RPC_COMMAND_REPLY,
+ .bodySize = static_cast<uint32_t>(sizeof(RpcWireReply) + reply.dataSize()),
+ };
RpcWireReply rpcReply{
.status = replyStatus,
};
- CommandData replyData(sizeof(RpcWireReply) + reply.dataSize());
- if (!replyData.valid()) {
- return NO_MEMORY;
- }
- 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()),
+ iovec iovs[]{
+ {&cmdReply, sizeof(RpcWireHeader)},
+ {&rpcReply, sizeof(RpcWireReply)},
+ {const_cast<uint8_t*>(reply.data()), reply.dataSize()},
};
-
- 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;
+ return rpcSend(connection, session, "reply", iovs, arraysize(iovs));
}
-status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) {
+status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const RpcWireHeader& command) {
LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
CommandData commandData(command.bodySize);
if (!commandData.valid()) {
return NO_MEMORY;
}
- if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) {
- return DEAD_OBJECT;
- }
+ iovec iov{commandData.data(), commandData.size()};
+ if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
+ return status;
- if (command.bodySize < sizeof(RpcWireAddress)) {
- ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
- sizeof(RpcWireAddress), command.bodySize);
- terminate();
+ if (command.bodySize != sizeof(RpcDecStrong)) {
+ ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
+ sizeof(RpcDecStrong), command.bodySize);
+ (void)session->shutdownAndWait(false);
return BAD_VALUE;
}
- RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
+ RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
- // TODO(b/182939933): heap allocation just for lookup
- auto addr = RpcAddress::fromRawEmbedded(address);
+ uint64_t addr = RpcWireAddress::toRaw(body->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());
+ ALOGE("Unknown binder address %" PRIu64 " for dec strong.", addr);
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();
+ ALOGE("While requesting dec strong, binder has been deleted at address %" PRIu64
+ ". Terminating!",
+ addr);
+ _l.unlock();
+ (void)session->shutdownAndWait(false);
return BAD_VALUE;
}
- if (it->second.timesSent == 0) {
- ALOGE("No record of sending binder, but requested decStrong: %s", addr.toString().c_str());
+ if (it->second.timesSent < body->amount) {
+ ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
+ it->second.timesSent, addr, body->amount);
return OK;
}
- LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %s",
- addr.toString().c_str());
+ LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
+ addr);
- sp<IBinder> tempHold;
+ LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+ it->second.timesSent);
- it->second.timesSent--;
- if (it->second.timesSent == 0) {
- tempHold = it->second.sentRef;
- it->second.sentRef = nullptr;
-
- if (it->second.timesRecd == 0) {
- mNodeForAddress.erase(it);
- }
- }
-
+ it->second.timesSent -= body->amount;
+ sp<IBinder> tempHold = tryEraseNode(it);
_l.unlock();
tempHold = nullptr; // destructor may make binder calls on this session
return OK;
}
+sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
+ sp<IBinder> ref;
+
+ if (it->second.timesSent == 0) {
+ ref = std::move(it->second.sentRef);
+
+ if (it->second.timesRecd == 0) {
+ LOG_ALWAYS_FATAL_IF(!it->second.asyncTodo.empty(),
+ "Can't delete binder w/ pending async transactions");
+ mNodeForAddress.erase(it);
+ }
+ }
+
+ return ref;
+}
+
+bool RpcState::nodeProgressAsyncNumber(BinderNode* node) {
+ // 2**64 =~ 10**19 =~ 1000 transactions per second for 585 million years to
+ // a single binder
+ if (node->asyncNumber >= std::numeric_limits<decltype(node->asyncNumber)>::max()) {
+ ALOGE("Out of async transaction IDs. Terminating");
+ return false;
+ }
+ node->asyncNumber++;
+ return true;
+}
+
} // namespace android
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 31f8a22..f4a0894 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -24,6 +24,8 @@
#include <optional>
#include <queue>
+#include <sys/uio.h>
+
namespace android {
struct RpcWireHeader;
@@ -42,6 +44,15 @@
#define LOG_RPC_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
#endif
+#define RPC_FLAKE_PRONE false
+
+#if RPC_FLAKE_PRONE
+void rpcMaybeWaitToFlake();
+#define MAYBE_WAIT_IN_FLAKE_MODE rpcMaybeWaitToFlake()
+#else
+#define MAYBE_WAIT_IN_FLAKE_MODE do {} while (false)
+#endif
+
/**
* Abstracts away management of ref counts and the wire format from
* RpcSession
@@ -51,38 +62,87 @@
RpcState();
~RpcState();
- // TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
- sp<IBinder> getRootObject(const base::unique_fd& fd, const sp<RpcSession>& session);
- status_t getMaxThreads(const base::unique_fd& fd, const sp<RpcSession>& session,
- size_t* maxThreadsOut);
- status_t getSessionId(const base::unique_fd& fd, const sp<RpcSession>& session,
- int32_t* sessionIdOut);
+ [[nodiscard]] status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint32_t* version);
+ [[nodiscard]] status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session);
+ [[nodiscard]] status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session);
- [[nodiscard]] status_t transact(const base::unique_fd& fd, const RpcAddress& address,
- uint32_t code, const Parcel& data,
+ // TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
+ sp<IBinder> getRootObject(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session);
+ [[nodiscard]] status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, size_t* maxThreadsOut);
+ [[nodiscard]] status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session,
+ std::vector<uint8_t>* sessionIdOut);
+
+ [[nodiscard]] status_t transact(const sp<RpcSession::RpcConnection>& connection,
+ const sp<IBinder>& address, uint32_t code, const Parcel& data,
const sp<RpcSession>& session, 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<RpcSession>& session);
+ [[nodiscard]] status_t transactAddress(const sp<RpcSession::RpcConnection>& connection,
+ uint64_t address, uint32_t code, const Parcel& data,
+ const sp<RpcSession>& session, Parcel* reply,
+ uint32_t flags);
+
+ /**
+ * The ownership model here carries an implicit strong refcount whenever a
+ * binder is sent across processes. Since we have a local strong count in
+ * sp<> over these objects, we only ever need to keep one of these. So,
+ * typically we tell the remote process that we drop all the implicit dec
+ * strongs, and we hold onto the last one. 'target' here is the target
+ * timesRecd (the number of remaining reference counts) we wish to keep.
+ * Typically this should be '0' or '1'. The target is used instead of an
+ * explicit decrement count in order to allow multiple threads to lower the
+ * number of counts simultaneously. Since we only lower the count to 0 when
+ * a binder is deleted, targets of '1' should only be sent when the caller
+ * owns a local strong reference to the binder. Larger targets may be used
+ * for testing, and to make the function generic, but generally this should
+ * be avoided because it would be hard to guarantee another thread doesn't
+ * lower the number of held refcounts to '1'. Note also, these refcounts
+ * must be sent actively. If they are sent when binders are deleted, this
+ * can cause leaks, since even remote binders carry an implicit strong ref
+ * when they are sent to another process.
+ */
+ [[nodiscard]] status_t sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint64_t address,
+ size_t target);
+
+ enum class CommandType {
+ ANY,
+ CONTROL_ONLY,
+ };
+ [[nodiscard]] status_t getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, CommandType type);
+ [[nodiscard]] status_t drainCommands(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, CommandType type);
/**
* Called by Parcel for outgoing binders. This implies one refcount of
* ownership to the outgoing binder.
*/
[[nodiscard]] status_t onBinderLeaving(const sp<RpcSession>& session, const sp<IBinder>& binder,
- RpcAddress* outAddress);
+ uint64_t* 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<RpcSession>& session, const RpcAddress& address);
+ [[nodiscard]] status_t onBinderEntering(const sp<RpcSession>& session, uint64_t address,
+ sp<IBinder>* out);
+ /**
+ * Called on incoming binders to update refcounting information. This should
+ * only be called when it is done as part of making progress on a
+ * transaction.
+ */
+ [[nodiscard]] status_t flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+ const sp<IBinder>& binder);
size_t countBinders();
void dump();
-private:
/**
* Called when reading or writing data to a session fails to clean up
* data associated with the session in order to cleanup binders.
@@ -99,7 +159,10 @@
* WARNING: RpcState is responsible for calling this when the session is
* no longer recoverable.
*/
- void terminate();
+ void clear();
+
+private:
+ void dumpLocked();
// Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps
// large allocations to avoid being requested from allocating too much data.
@@ -115,21 +178,26 @@
size_t mSize;
};
- [[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 rpcSend(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const char* what, iovec* iovs,
+ int niovs, const std::function<status_t()>& altPoll = nullptr);
+ [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, const char* what, iovec* iovs,
+ int niovs);
- [[nodiscard]] status_t waitForReply(const base::unique_fd& fd, const sp<RpcSession>& session,
- Parcel* reply);
- [[nodiscard]] status_t processServerCommand(const base::unique_fd& fd,
- const sp<RpcSession>& session,
- const RpcWireHeader& command);
- [[nodiscard]] status_t processTransact(const base::unique_fd& fd, const sp<RpcSession>& session,
+ [[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, Parcel* reply);
+ [[nodiscard]] status_t processCommand(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session,
+ const RpcWireHeader& command, CommandType type);
+ [[nodiscard]] status_t processTransact(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session,
const RpcWireHeader& command);
- [[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
+ [[nodiscard]] status_t processTransactInternal(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session,
CommandData transactionData);
- [[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
+ [[nodiscard]] status_t processDecStrong(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session,
const RpcWireHeader& command);
struct BinderNode {
@@ -163,6 +231,7 @@
// async transaction queue, _only_ for local binder
struct AsyncTodo {
+ sp<IBinder> ref;
CommandData data;
uint64_t asyncNumber = 0;
@@ -179,10 +248,20 @@
// (no additional data specific to remote binders)
};
+ // checks if there is any reference left to a node and erases it. If erase
+ // happens, and there is a strong reference to the binder kept by
+ // binderNode, this returns that strong reference, so that it can be
+ // dropped after any locks are removed.
+ sp<IBinder> tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it);
+ // true - success
+ // false - session shutdown, halt
+ [[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node);
+
std::mutex mNodeMutex;
bool mTerminated = false;
+ uint32_t mNextId = 0;
// binders known by both sides of a session
- std::map<RpcAddress, BinderNode> mNodeForAddress;
+ std::map<uint64_t, BinderNode> mNodeForAddress;
};
} // namespace android
diff --git a/libs/binder/RpcTlsUtils.cpp b/libs/binder/RpcTlsUtils.cpp
new file mode 100644
index 0000000..f3ca02a
--- /dev/null
+++ b/libs/binder/RpcTlsUtils.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcTlsUtils"
+#include <log/log.h>
+
+#include <binder/RpcTlsUtils.h>
+
+#include "Utils.h"
+
+namespace android {
+
+namespace {
+
+static_assert(sizeof(unsigned char) == sizeof(uint8_t));
+
+template <typename PemReadBioFn,
+ typename T = std::remove_pointer_t<std::invoke_result_t<
+ PemReadBioFn, BIO*, std::nullptr_t, std::nullptr_t, std::nullptr_t>>>
+bssl::UniquePtr<T> fromPem(const std::vector<uint8_t>& data, PemReadBioFn fn) {
+ if (data.size() > std::numeric_limits<int>::max()) return nullptr;
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(data.data(), static_cast<int>(data.size())));
+ return bssl::UniquePtr<T>(fn(bio.get(), nullptr, nullptr, nullptr));
+}
+
+template <typename D2iFn,
+ typename T = std::remove_pointer_t<
+ std::invoke_result_t<D2iFn, std::nullptr_t, const unsigned char**, long>>>
+bssl::UniquePtr<T> fromDer(const std::vector<uint8_t>& data, D2iFn fn) {
+ if (data.size() > std::numeric_limits<long>::max()) return nullptr;
+ const unsigned char* dataPtr = data.data();
+ auto expectedEnd = dataPtr + data.size();
+ bssl::UniquePtr<T> ret(fn(nullptr, &dataPtr, static_cast<long>(data.size())));
+ if (dataPtr != expectedEnd) {
+ ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - dataPtr);
+ return nullptr;
+ }
+ return ret;
+}
+
+template <typename T, typename WriteBioFn = int (*)(BIO*, T*)>
+std::vector<uint8_t> serialize(T* object, WriteBioFn writeBio) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ TEST_AND_RETURN({}, writeBio(bio.get(), object));
+ const uint8_t* data;
+ size_t len;
+ TEST_AND_RETURN({}, BIO_mem_contents(bio.get(), &data, &len));
+ return std::vector<uint8_t>(data, data + len);
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& data,
+ RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return fromPem(data, PEM_read_bio_X509);
+ case RpcCertificateFormat::DER:
+ return fromDer(data, d2i_X509);
+ }
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return serialize(x509, PEM_write_bio_X509);
+ case RpcCertificateFormat::DER:
+ return serialize(x509, i2d_X509_bio);
+ }
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+bssl::UniquePtr<EVP_PKEY> deserializeUnencryptedPrivatekey(const std::vector<uint8_t>& data,
+ RpcKeyFormat format) {
+ switch (format) {
+ case RpcKeyFormat::PEM:
+ return fromPem(data, PEM_read_bio_PrivateKey);
+ case RpcKeyFormat::DER:
+ return fromDer(data, d2i_AutoPrivateKey);
+ }
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeUnencryptedPrivatekey(EVP_PKEY* pkey, RpcKeyFormat format) {
+ switch (format) {
+ case RpcKeyFormat::PEM:
+ return serialize(pkey, [](BIO* bio, EVP_PKEY* pkey) {
+ return PEM_write_bio_PrivateKey(bio, pkey, nullptr /* enc */, nullptr /* kstr */,
+ 0 /* klen */, nullptr, nullptr);
+ });
+ case RpcKeyFormat::DER:
+ return serialize(pkey, i2d_PrivateKey_bio);
+ }
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+} // namespace android
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
new file mode 100644
index 0000000..7cfc780
--- /dev/null
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcRawTransport"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <binder/RpcTransportRaw.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+namespace android {
+
+namespace {
+
+// RpcTransport with TLS disabled.
+class RpcTransportRaw : public RpcTransport {
+public:
+ explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+ status_t peek(void* buf, size_t size, size_t* out_size) override {
+ ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
+ if (ret < 0) {
+ int savedErrno = errno;
+ if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+
+ LOG_RPC_DETAIL("RpcTransport peek(): %s", strerror(savedErrno));
+ return -savedErrno;
+ }
+
+ *out_size = static_cast<size_t>(ret);
+ return OK;
+ }
+
+ template <typename SendOrReceive>
+ status_t interruptableReadOrWrite(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ SendOrReceive sendOrReceiveFun, const char* funName,
+ int16_t event, const std::function<status_t()>& altPoll) {
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ if (niovs < 0) {
+ return BAD_VALUE;
+ }
+
+ // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+ // may never know we should be shutting down.
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+
+ // If iovs has one or more empty vectors at the end and
+ // we somehow advance past all the preceding vectors and
+ // pass some or all of the empty ones to sendmsg/recvmsg,
+ // the call will return processSize == 0. In that case
+ // we should be returning OK but instead return DEAD_OBJECT.
+ // To avoid this problem, we make sure here that the last
+ // vector at iovs[niovs - 1] has a non-zero length.
+ while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+ niovs--;
+ }
+ if (niovs == 0) {
+ // The vectors are all empty, so we have nothing to send.
+ return OK;
+ }
+
+ bool havePolled = false;
+ while (true) {
+ msghdr msg{
+ .msg_iov = iovs,
+ // posix uses int, glibc uses size_t. niovs is a
+ // non-negative int and can be cast to either.
+ .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs),
+ };
+ ssize_t processSize =
+ TEMP_FAILURE_RETRY(sendOrReceiveFun(mSocket.get(), &msg, MSG_NOSIGNAL));
+
+ if (processSize < 0) {
+ int savedErrno = errno;
+
+ // Still return the error on later passes, since it would expose
+ // a problem with polling
+ if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+ LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+ return -savedErrno;
+ }
+ } else if (processSize == 0) {
+ return DEAD_OBJECT;
+ } else {
+ while (processSize > 0 && niovs > 0) {
+ auto& iov = iovs[0];
+ if (static_cast<size_t>(processSize) < iov.iov_len) {
+ // Advance the base of the current iovec
+ iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+ iov.iov_len -= processSize;
+ break;
+ }
+
+ // The current iovec was fully written
+ processSize -= iov.iov_len;
+ iovs++;
+ niovs--;
+ }
+ if (niovs == 0) {
+ LOG_ALWAYS_FATAL_IF(processSize > 0,
+ "Reached the end of iovecs "
+ "with %zd bytes remaining",
+ processSize);
+ return OK;
+ }
+ }
+
+ if (altPoll) {
+ if (status_t status = altPoll(); status != OK) return status;
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+ } else {
+ if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
+ status != OK)
+ return status;
+ if (!havePolled) havePolled = true;
+ }
+ }
+ }
+
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) override {
+ return interruptableReadOrWrite(fdTrigger, iovs, niovs, sendmsg, "sendmsg", POLLOUT,
+ altPoll);
+ }
+
+ status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) override {
+ return interruptableReadOrWrite(fdTrigger, iovs, niovs, recvmsg, "recvmsg", POLLIN,
+ altPoll);
+ }
+
+private:
+ base::unique_fd mSocket;
+};
+
+// RpcTransportCtx with TLS disabled.
+class RpcTransportCtxRaw : public RpcTransportCtx {
+public:
+ std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
+ return std::make_unique<RpcTransportRaw>(std::move(fd));
+ }
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
+};
+
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newServerCtx() const {
+ return std::make_unique<RpcTransportCtxRaw>();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newClientCtx() const {
+ return std::make_unique<RpcTransportCtxRaw>();
+}
+
+const char *RpcTransportCtxFactoryRaw::toCString() const {
+ return "raw";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryRaw::make() {
+ return std::unique_ptr<RpcTransportCtxFactoryRaw>(new RpcTransportCtxFactoryRaw());
+}
+
+} // namespace android
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
new file mode 100644
index 0000000..bc68c37
--- /dev/null
+++ b/libs/binder/RpcTransportTls.cpp
@@ -0,0 +1,557 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcTransportTls"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <openssl/bn.h>
+#include <openssl/ssl.h>
+
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransportTls.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+#include "Utils.h"
+
+#define SHOULD_LOG_TLS_DETAIL false
+
+#if SHOULD_LOG_TLS_DETAIL
+#define LOG_TLS_DETAIL(...) ALOGI(__VA_ARGS__)
+#else
+#define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
+#endif
+
+namespace android {
+namespace {
+
+// Implement BIO for socket that ignores SIGPIPE.
+int socketNew(BIO* bio) {
+ BIO_set_data(bio, reinterpret_cast<void*>(-1));
+ BIO_set_init(bio, 0);
+ return 1;
+}
+int socketFree(BIO* bio) {
+ LOG_ALWAYS_FATAL_IF(bio == nullptr);
+ return 1;
+}
+int socketRead(BIO* bio, char* buf, int size) {
+ android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+ int ret = TEMP_FAILURE_RETRY(::recv(fd.get(), buf, size, MSG_NOSIGNAL));
+ BIO_clear_retry_flags(bio);
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ BIO_set_retry_read(bio);
+ }
+ return ret;
+}
+
+int socketWrite(BIO* bio, const char* buf, int size) {
+ android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+ int ret = TEMP_FAILURE_RETRY(::send(fd.get(), buf, size, MSG_NOSIGNAL));
+ BIO_clear_retry_flags(bio);
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ BIO_set_retry_write(bio);
+ }
+ return ret;
+}
+
+long socketCtrl(BIO* bio, int cmd, long num, void*) { // NOLINT
+ android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+ if (cmd == BIO_CTRL_FLUSH) return 1;
+ LOG_ALWAYS_FATAL("sockCtrl(fd=%d, %d, %ld)", fd.get(), cmd, num);
+ return 0;
+}
+
+bssl::UniquePtr<BIO> newSocketBio(android::base::borrowed_fd fd) {
+ static const BIO_METHOD* gMethods = ([] {
+ auto methods = BIO_meth_new(BIO_get_new_index(), "socket_no_signal");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_write(methods, socketWrite), "BIO_meth_set_write");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_read(methods, socketRead), "BIO_meth_set_read");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_ctrl(methods, socketCtrl), "BIO_meth_set_ctrl");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_create(methods, socketNew), "BIO_meth_set_create");
+ LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_destroy(methods, socketFree), "BIO_meth_set_destroy");
+ return methods;
+ })();
+ bssl::UniquePtr<BIO> ret(BIO_new(gMethods));
+ if (ret == nullptr) return nullptr;
+ BIO_set_data(ret.get(), reinterpret_cast<void*>(fd.get()));
+ BIO_set_init(ret.get(), 1);
+ return ret;
+}
+
+[[maybe_unused]] void sslDebugLog(const SSL* ssl, int type, int value) {
+ switch (type) {
+ case SSL_CB_HANDSHAKE_START:
+ LOG_TLS_DETAIL("Handshake started.");
+ break;
+ case SSL_CB_HANDSHAKE_DONE:
+ LOG_TLS_DETAIL("Handshake done.");
+ break;
+ case SSL_CB_ACCEPT_LOOP:
+ LOG_TLS_DETAIL("Handshake progress: %s", SSL_state_string_long(ssl));
+ break;
+ default:
+ LOG_TLS_DETAIL("SSL Debug Log: type = %d, value = %d", type, value);
+ break;
+ }
+}
+
+// Helper class to ErrorQueue::toString
+class ErrorQueueString {
+public:
+ static std::string toString() {
+ ErrorQueueString thiz;
+ ERR_print_errors_cb(staticCallback, &thiz);
+ return thiz.mSs.str();
+ }
+
+private:
+ static int staticCallback(const char* str, size_t len, void* ctx) {
+ return reinterpret_cast<ErrorQueueString*>(ctx)->callback(str, len);
+ }
+ int callback(const char* str, size_t len) {
+ if (len == 0) return 1; // continue
+ // ERR_print_errors_cb place a new line at the end, but it doesn't say so in the API.
+ if (str[len - 1] == '\n') len -= 1;
+ if (!mIsFirst) {
+ mSs << '\n';
+ }
+ mSs << std::string_view(str, len);
+ mIsFirst = false;
+ return 1; // continue
+ }
+ std::stringstream mSs;
+ bool mIsFirst = true;
+};
+
+// Handles libssl's error queue.
+//
+// Call into any of its member functions to ensure the error queue is properly handled or cleared.
+// If the error queue is not handled or cleared, the destructor will abort.
+class ErrorQueue {
+public:
+ ~ErrorQueue() { LOG_ALWAYS_FATAL_IF(!mHandled); }
+
+ // Clear the error queue.
+ void clear() {
+ ERR_clear_error();
+ mHandled = true;
+ }
+
+ // Stores the error queue in |ssl| into a string, then clears the error queue.
+ std::string toString() {
+ auto ret = ErrorQueueString::toString();
+ // Though ERR_print_errors_cb should have cleared it, it is okay to clear again.
+ clear();
+ return ret;
+ }
+
+ status_t toStatus(int sslError, const char* fnString) {
+ switch (sslError) {
+ case SSL_ERROR_SYSCALL: {
+ auto queue = toString();
+ LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
+ SSL_error_description(sslError), queue.c_str());
+ return DEAD_OBJECT;
+ }
+ default: {
+ auto queue = toString();
+ ALOGE("%s(): %s. Error queue: %s", fnString, SSL_error_description(sslError),
+ queue.c_str());
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ // |sslError| should be from Ssl::getError().
+ // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+ // return error. Also return error if |fdTrigger| is triggered before or during poll().
+ status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
+ const char* fnString, int additionalEvent,
+ const std::function<status_t()>& altPoll) {
+ switch (sslError) {
+ case SSL_ERROR_WANT_READ:
+ return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
+ case SSL_ERROR_WANT_WRITE:
+ return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
+ default:
+ return toStatus(sslError, fnString);
+ }
+ }
+
+private:
+ bool mHandled = false;
+
+ status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
+ const char* fnString, const std::function<status_t()>& altPoll) {
+ status_t ret;
+ if (altPoll) {
+ ret = altPoll();
+ if (fdTrigger->isTriggered()) ret = DEAD_OBJECT;
+ } else {
+ ret = fdTrigger->triggerablePoll(fd, event);
+ }
+
+ if (ret != OK && ret != DEAD_OBJECT) {
+ ALOGE("poll error while after %s(): %s", fnString, statusToString(ret).c_str());
+ }
+ clear();
+ return ret;
+ }
+};
+
+// Helper to call a function, with its return value instantiable.
+template <typename Fn, typename... Args>
+struct FuncCaller {
+ struct Monostate {};
+ static constexpr bool sIsVoid = std::is_void_v<std::invoke_result_t<Fn, Args...>>;
+ using Result = std::conditional_t<sIsVoid, Monostate, std::invoke_result_t<Fn, Args...>>;
+ static inline Result call(Fn fn, Args&&... args) {
+ if constexpr (std::is_void_v<std::invoke_result_t<Fn, Args...>>) {
+ std::invoke(fn, std::forward<Args>(args)...);
+ return {};
+ } else {
+ return std::invoke(fn, std::forward<Args>(args)...);
+ }
+ }
+};
+
+// Helper to Ssl::call(). Returns the result to the SSL_* function as well as an ErrorQueue object.
+template <typename Fn, typename... Args>
+struct SslCaller {
+ using RawCaller = FuncCaller<Fn, SSL*, Args...>;
+ struct ResultAndErrorQueue {
+ typename RawCaller::Result result;
+ ErrorQueue errorQueue;
+ };
+ static inline ResultAndErrorQueue call(Fn fn, SSL* ssl, Args&&... args) {
+ LOG_ALWAYS_FATAL_IF(ssl == nullptr);
+ auto result = RawCaller::call(fn, std::forward<SSL*>(ssl), std::forward<Args>(args)...);
+ return ResultAndErrorQueue{std::move(result), ErrorQueue()};
+ }
+};
+
+// A wrapper over bssl::UniquePtr<SSL>. This class ensures that all SSL_* functions are called
+// through call(), which returns an ErrorQueue object that requires the caller to either handle
+// or clear it.
+// Example:
+// auto [ret, errorQueue] = ssl.call(SSL_read, buf, size);
+// if (ret >= 0) errorQueue.clear();
+// else ALOGE("%s", errorQueue.toString().c_str());
+class Ssl {
+public:
+ explicit Ssl(bssl::UniquePtr<SSL> ssl) : mSsl(std::move(ssl)) {
+ LOG_ALWAYS_FATAL_IF(mSsl == nullptr);
+ }
+
+ template <typename Fn, typename... Args>
+ inline typename SslCaller<Fn, Args...>::ResultAndErrorQueue call(Fn fn, Args&&... args) {
+ return SslCaller<Fn, Args...>::call(fn, mSsl.get(), std::forward<Args>(args)...);
+ }
+
+ int getError(int ret) {
+ LOG_ALWAYS_FATAL_IF(mSsl == nullptr);
+ return SSL_get_error(mSsl.get(), ret);
+ }
+
+private:
+ bssl::UniquePtr<SSL> mSsl;
+};
+
+class RpcTransportTls : public RpcTransport {
+public:
+ RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
+ : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
+ status_t peek(void* buf, size_t size, size_t* out_size) override;
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) override;
+ status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) override;
+
+private:
+ android::base::unique_fd mSocket;
+ Ssl mSsl;
+};
+
+// Error code is errno.
+status_t RpcTransportTls::peek(void* buf, size_t size, size_t* out_size) {
+ size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
+ auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
+ if (ret < 0) {
+ int err = mSsl.getError(ret);
+ if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
+ // Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
+ // Like RpcTransportRaw::peek(), don't handle it here.
+ errorQueue.clear();
+ return WOULD_BLOCK;
+ }
+ return errorQueue.toStatus(err, "SSL_peek");
+ }
+ errorQueue.clear();
+ LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
+ *out_size = static_cast<size_t>(ret);
+ return OK;
+}
+
+status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) {
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ if (niovs < 0) return BAD_VALUE;
+
+ // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
+ // once. The trigger is also checked via triggerablePoll() after every SSL_write().
+ if (fdTrigger->isTriggered()) return DEAD_OBJECT;
+
+ size_t size = 0;
+ for (int i = 0; i < niovs; i++) {
+ const iovec& iov = iovs[i];
+ if (iov.iov_len == 0) {
+ continue;
+ }
+ size += iov.iov_len;
+
+ auto buffer = reinterpret_cast<const uint8_t*>(iov.iov_base);
+ const uint8_t* end = buffer + iov.iov_len;
+ while (buffer < end) {
+ size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+ auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo);
+ if (writeSize > 0) {
+ buffer += writeSize;
+ errorQueue.clear();
+ continue;
+ }
+ // SSL_write() should never return 0 unless BIO_write were to return 0.
+ int sslError = mSsl.getError(writeSize);
+ // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
+ // triggerablePoll()-ed. Then additionalEvent is no longer necessary.
+ status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ "SSL_write", POLLIN, altPoll);
+ if (pollStatus != OK) return pollStatus;
+ // Do not advance buffer. Try SSL_write() again.
+ }
+ }
+ LOG_TLS_DETAIL("TLS: Sent %zu bytes!", size);
+ return OK;
+}
+
+status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
+ const std::function<status_t()>& altPoll) {
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ if (niovs < 0) return BAD_VALUE;
+
+ // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
+ // once. The trigger is also checked via triggerablePoll() after every SSL_write().
+ if (fdTrigger->isTriggered()) return DEAD_OBJECT;
+
+ size_t size = 0;
+ for (int i = 0; i < niovs; i++) {
+ const iovec& iov = iovs[i];
+ if (iov.iov_len == 0) {
+ continue;
+ }
+ size += iov.iov_len;
+
+ auto buffer = reinterpret_cast<uint8_t*>(iov.iov_base);
+ const uint8_t* end = buffer + iov.iov_len;
+ while (buffer < end) {
+ size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+ auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo);
+ if (readSize > 0) {
+ buffer += readSize;
+ errorQueue.clear();
+ continue;
+ }
+ if (readSize == 0) {
+ // SSL_read() only returns 0 on EOF.
+ errorQueue.clear();
+ return DEAD_OBJECT;
+ }
+ int sslError = mSsl.getError(readSize);
+ status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ "SSL_read", 0, altPoll);
+ if (pollStatus != OK) return pollStatus;
+ // Do not advance buffer. Try SSL_read() again.
+ }
+ }
+ LOG_TLS_DETAIL("TLS: Received %zu bytes!", size);
+ return OK;
+}
+
+// For |ssl|, set internal FD to |fd|, and do handshake. Handshake is triggerable by |fdTrigger|.
+bool setFdAndDoHandshake(Ssl* ssl, android::base::borrowed_fd fd, FdTrigger* fdTrigger) {
+ bssl::UniquePtr<BIO> bio = newSocketBio(fd);
+ TEST_AND_RETURN(false, bio != nullptr);
+ auto [_, errorQueue] = ssl->call(SSL_set_bio, bio.get(), bio.get());
+ (void)bio.release(); // SSL_set_bio takes ownership.
+ errorQueue.clear();
+
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ while (true) {
+ auto [ret, errorQueue] = ssl->call(SSL_do_handshake);
+ if (ret > 0) {
+ errorQueue.clear();
+ return true;
+ }
+ if (ret == 0) {
+ // SSL_do_handshake() only returns 0 on EOF.
+ ALOGE("SSL_do_handshake(): EOF: %s", errorQueue.toString().c_str());
+ return false;
+ }
+ int sslError = ssl->getError(ret);
+ status_t pollStatus =
+ errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake", 0, {});
+ if (pollStatus != OK) return false;
+ }
+}
+
+class RpcTransportCtxTls : public RpcTransportCtx {
+public:
+ template <typename Impl,
+ typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
+ static std::unique_ptr<RpcTransportCtxTls> create(
+ std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth);
+ std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
+ FdTrigger* fdTrigger) const override;
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
+
+protected:
+ static ssl_verify_result_t sslCustomVerify(SSL* ssl, uint8_t* outAlert);
+ virtual void preHandshake(Ssl* ssl) const = 0;
+ bssl::UniquePtr<SSL_CTX> mCtx;
+ std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
+};
+
+std::vector<uint8_t> RpcTransportCtxTls::getCertificate(RpcCertificateFormat format) const {
+ X509* x509 = SSL_CTX_get0_certificate(mCtx.get()); // does not own
+ return serializeCertificate(x509, format);
+}
+
+// Verify by comparing the leaf of peer certificate with every certificate in
+// mTrustedPeerCertificates. Does not support certificate chains.
+ssl_verify_result_t RpcTransportCtxTls::sslCustomVerify(SSL* ssl, uint8_t* outAlert) {
+ LOG_ALWAYS_FATAL_IF(outAlert == nullptr);
+ const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+
+ auto ctx = SSL_get_SSL_CTX(ssl); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(ctx == nullptr);
+ // void* -> RpcTransportCtxTls*
+ auto rpcTransportCtxTls = reinterpret_cast<RpcTransportCtxTls*>(SSL_CTX_get_app_data(ctx));
+ LOG_ALWAYS_FATAL_IF(rpcTransportCtxTls == nullptr);
+
+ status_t verifyStatus = rpcTransportCtxTls->mCertVerifier->verify(ssl, outAlert);
+ if (verifyStatus == OK) {
+ return ssl_verify_ok;
+ }
+ LOG_TLS_DETAIL("%s: Failed to verify client: status = %s, alert = %s", logPrefix,
+ statusToString(verifyStatus).c_str(), SSL_alert_desc_string_long(*outAlert));
+ return ssl_verify_invalid;
+}
+
+// Common implementation for creating server and client contexts. The child class, |Impl|, is
+// provided as a template argument so that this function can initialize an |Impl| object.
+template <typename Impl, typename>
+std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create(
+ std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth) {
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ TEST_AND_RETURN(nullptr, ctx != nullptr);
+
+ if (status_t authStatus = auth->configure(ctx.get()); authStatus != OK) {
+ ALOGE("%s: Failed to configure auth info: %s", __PRETTY_FUNCTION__,
+ statusToString(authStatus).c_str());
+ return nullptr;
+ };
+
+ // Enable two-way authentication by setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT on server.
+ // Client ignores SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag.
+ SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ sslCustomVerify);
+
+ // Require at least TLS 1.3
+ TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
+
+ if constexpr (SHOULD_LOG_TLS_DETAIL) { // NOLINT
+ SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
+ }
+
+ auto ret = std::make_unique<Impl>();
+ // RpcTransportCtxTls* -> void*
+ TEST_AND_RETURN(nullptr, SSL_CTX_set_app_data(ctx.get(), reinterpret_cast<void*>(ret.get())));
+ ret->mCtx = std::move(ctx);
+ ret->mCertVerifier = std::move(verifier);
+ return ret;
+}
+
+std::unique_ptr<RpcTransport> RpcTransportCtxTls::newTransport(android::base::unique_fd fd,
+ FdTrigger* fdTrigger) const {
+ bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
+ TEST_AND_RETURN(nullptr, ssl != nullptr);
+ Ssl wrapped(std::move(ssl));
+
+ preHandshake(&wrapped);
+ TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, fd, fdTrigger));
+ return std::make_unique<RpcTransportTls>(std::move(fd), std::move(wrapped));
+}
+
+class RpcTransportCtxTlsServer : public RpcTransportCtxTls {
+protected:
+ void preHandshake(Ssl* ssl) const override {
+ ssl->call(SSL_set_accept_state).errorQueue.clear();
+ }
+};
+
+class RpcTransportCtxTlsClient : public RpcTransportCtxTls {
+protected:
+ void preHandshake(Ssl* ssl) const override {
+ ssl->call(SSL_set_connect_state).errorQueue.clear();
+ }
+};
+
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
+ return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier,
+ mAuth.get());
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
+ return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier,
+ mAuth.get());
+}
+
+const char* RpcTransportCtxFactoryTls::toCString() const {
+ return "tls";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make(
+ std::shared_ptr<RpcCertificateVerifier> verifier, std::unique_ptr<RpcAuth> auth) {
+ if (verifier == nullptr) {
+ ALOGE("%s: Must provide a certificate verifier", __PRETTY_FUNCTION__);
+ return nullptr;
+ }
+ if (auth == nullptr) {
+ ALOGE("%s: Must provide an auth provider", __PRETTY_FUNCTION__);
+ return nullptr;
+ }
+ return std::unique_ptr<RpcTransportCtxFactoryTls>(
+ new RpcTransportCtxFactoryTls(std::move(verifier), std::move(auth)));
+}
+
+} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index c5fa008..171550e 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -20,6 +20,61 @@
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wpadded"
+constexpr uint8_t RPC_CONNECTION_OPTION_INCOMING = 0x1; // default is outgoing
+
+constexpr uint32_t RPC_WIRE_ADDRESS_OPTION_CREATED = 1 << 0; // distinguish from '0' address
+constexpr uint32_t RPC_WIRE_ADDRESS_OPTION_FOR_SERVER = 1 << 1;
+
+struct RpcWireAddress {
+ uint32_t options;
+ uint32_t address;
+
+ static inline RpcWireAddress fromRaw(uint64_t raw) {
+ return *reinterpret_cast<RpcWireAddress*>(&raw);
+ }
+ static inline uint64_t toRaw(RpcWireAddress addr) {
+ return *reinterpret_cast<uint64_t*>(&addr);
+ }
+};
+static_assert(sizeof(RpcWireAddress) == sizeof(uint64_t));
+
+/**
+ * This is sent to an RpcServer in order to request a new connection is created,
+ * either as part of a new session or an existing session
+ */
+struct RpcConnectionHeader {
+ uint32_t version; // maximum supported by caller
+ uint8_t options;
+ uint8_t reservered[9];
+ // Follows is sessionIdSize bytes.
+ // if size is 0, this is requesting a new session.
+ uint16_t sessionIdSize;
+};
+static_assert(sizeof(RpcConnectionHeader) == 16);
+
+/**
+ * In response to an RpcConnectionHeader which corresponds to a new session,
+ * this returns information to the server.
+ */
+struct RpcNewSessionResponse {
+ uint32_t version; // maximum supported by callee <= maximum supported by caller
+ uint8_t reserved[4];
+};
+static_assert(sizeof(RpcNewSessionResponse) == 8);
+
+#define RPC_CONNECTION_INIT_OKAY "cci"
+
+/**
+ * Whenever a client connection is setup, this is sent as the initial
+ * transaction. The main use of this is in order to control the timing for when
+ * an incoming connection is setup.
+ */
+struct RpcOutgoingConnectionInit {
+ char msg[4];
+ uint8_t reserved[4];
+};
+static_assert(sizeof(RpcOutgoingConnectionInit) == 8);
+
enum : uint32_t {
/**
* follows is RpcWireTransaction, if flags != oneway, reply w/ RPC_COMMAND_REPLY expected
@@ -30,7 +85,7 @@
*/
RPC_COMMAND_REPLY,
/**
- * follows is RpcWireAddress
+ * follows is RpcDecStrong
*
* note - this in the protocol directly instead of as a 'special
* transaction' in order to keep it as lightweight as possible (we don't
@@ -51,8 +106,6 @@
RPC_SPECIAL_TRANSACT_GET_SESSION_ID = 2,
};
-constexpr int32_t RPC_SESSION_ID_NEW = -1;
-
// serialization is like:
// |RpcWireHeader|struct desginated by 'command'| (over and over again)
@@ -62,10 +115,14 @@
uint32_t reserved[2];
};
+static_assert(sizeof(RpcWireHeader) == 16);
-struct RpcWireAddress {
- uint8_t address[32];
+struct RpcDecStrong {
+ RpcWireAddress address;
+ uint32_t amount;
+ uint32_t reserved;
};
+static_assert(sizeof(RpcDecStrong) == 16);
struct RpcWireTransaction {
RpcWireAddress address;
@@ -76,13 +133,15 @@
uint32_t reserved[4];
- uint8_t data[0];
+ uint8_t data[];
};
+static_assert(sizeof(RpcWireTransaction) == 40);
struct RpcWireReply {
int32_t status; // transact return
- uint8_t data[0];
+ uint8_t data[];
};
+static_assert(sizeof(RpcWireReply) == 4);
#pragma clang diagnostic pop
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
new file mode 100644
index 0000000..194254a
--- /dev/null
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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 "ServiceManagerHost.h"
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "UtilsHost.h"
+
+namespace android {
+
+namespace {
+
+const void* kDeviceServiceExtraId = "DeviceServiceExtra";
+
+// Parse stdout of program execution to string. If any error, return 0.
+unsigned int parsePortNumber(const std::string& out, const std::string& what) {
+ auto trimmed = android::base::Trim(out);
+ unsigned int port = 0;
+ if (!android::base::ParseUint(trimmed, &port)) {
+ int savedErrno = errno;
+ ALOGE("%s is not a valid %s: %s", trimmed.c_str(), what.c_str(), strerror(savedErrno));
+ return 0;
+ }
+ if (port == 0) {
+ ALOGE("0 is not a valid %s", what.c_str());
+ return 0; // explicitly
+ }
+ return port;
+}
+
+// RAII object for adb forwarding
+class AdbForwarder {
+public:
+ AdbForwarder() = default;
+ static std::optional<AdbForwarder> forward(unsigned int devicePort);
+ AdbForwarder(AdbForwarder&& other) noexcept { (*this) = std::move(other); }
+ AdbForwarder& operator=(AdbForwarder&&) noexcept;
+ ~AdbForwarder();
+ [[nodiscard]] const std::optional<unsigned int>& hostPort() const { return mPort; }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(AdbForwarder);
+ explicit AdbForwarder(unsigned int port) : mPort(port) {}
+ std::optional<unsigned int> mPort;
+};
+std::optional<AdbForwarder> AdbForwarder::forward(unsigned int devicePort) {
+ auto result =
+ execute({"adb", "forward", "tcp:0", "tcp:" + std::to_string(devicePort)}, nullptr);
+ if (!result.ok()) {
+ ALOGE("Unable to run `adb forward tcp:0 tcp:%d`: %s", devicePort,
+ result.error().message().c_str());
+ return std::nullopt;
+ }
+ // Must end with exit code 0 (`has_value() && value() == 0`)
+ if (result->exitCode.value_or(1) != 0) {
+ ALOGE("Unable to run `adb forward tcp:0 tcp:%d`, command exits with %s", devicePort,
+ result->toString().c_str());
+ return std::nullopt;
+ }
+ if (!result->stderrStr.empty()) {
+ LOG_HOST("`adb forward tcp:0 tcp:%d` writes to stderr: %s", devicePort,
+ result->stderrStr.c_str());
+ }
+
+ unsigned int hostPort = parsePortNumber(result->stdoutStr, "host port");
+ if (hostPort == 0) return std::nullopt;
+
+ return AdbForwarder(hostPort);
+}
+
+AdbForwarder& AdbForwarder::operator=(AdbForwarder&& other) noexcept {
+ std::swap(mPort, other.mPort);
+ return *this;
+}
+
+AdbForwarder::~AdbForwarder() {
+ if (!mPort.has_value()) return;
+
+ auto result = execute({"adb", "forward", "--remove", "tcp:" + std::to_string(*mPort)}, nullptr);
+ if (!result.ok()) {
+ ALOGE("Unable to run `adb forward --remove tcp:%d`: %s", *mPort,
+ result.error().message().c_str());
+ return;
+ }
+ // Must end with exit code 0 (`has_value() && value() == 0`)
+ if (result->exitCode.value_or(1) != 0) {
+ ALOGE("Unable to run `adb forward --remove tcp:%d`, command exits with %s", *mPort,
+ result->toString().c_str());
+ return;
+ }
+ if (!result->stderrStr.empty()) {
+ LOG_HOST("`adb forward --remove tcp:%d` writes to stderr: %s", *mPort,
+ result->stderrStr.c_str());
+ }
+
+ LOG_HOST("Successfully run `adb forward --remove tcp:%d`", *mPort);
+}
+
+void cleanupCommandResult(const void* id, void* obj, void* /* cookie */) {
+ LOG_ALWAYS_FATAL_IF(id != kDeviceServiceExtraId,
+ "cleanupCommandResult invoked with mismatched ID %p, "
+ "expected %p",
+ id, kDeviceServiceExtraId);
+ auto ptr = static_cast<CommandResult*>(obj);
+ delete ptr;
+}
+
+} // namespace
+
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs,
+ const RpcDelegateServiceManagerOptions& options) {
+ std::vector<std::string> prefix{"adb", "shell", "servicedispatcher"};
+ serviceDispatcherArgs.insert(serviceDispatcherArgs.begin(), prefix.begin(), prefix.end());
+
+ auto result = execute(std::move(serviceDispatcherArgs), &CommandResult::stdoutEndsWithNewLine);
+ if (!result.ok()) {
+ ALOGE("%s", result.error().message().c_str());
+ return nullptr;
+ }
+
+ // `servicedispatcher` process must be alive to keep the port open.
+ if (result->exitCode.has_value()) {
+ ALOGE("Command exits with: %s", result->toString().c_str());
+ return nullptr;
+ }
+ if (!result->stderrStr.empty()) {
+ LOG_HOST("servicedispatcher writes to stderr: %s", result->stderrStr.c_str());
+ }
+
+ if (!result->stdoutEndsWithNewLine()) {
+ ALOGE("Unexpected command result: %s", result->toString().c_str());
+ return nullptr;
+ }
+
+ unsigned int devicePort = parsePortNumber(result->stdoutStr, "device port");
+ if (devicePort == 0) return nullptr;
+
+ auto forwardResult = AdbForwarder::forward(devicePort);
+ if (!forwardResult.has_value()) {
+ return nullptr;
+ }
+ LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
+
+ auto rpcSession = RpcSession::make();
+ if (options.maxOutgoingThreads.has_value()) {
+ rpcSession->setMaxOutgoingThreads(*options.maxOutgoingThreads);
+ }
+
+ if (status_t status = rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort());
+ status != OK) {
+ ALOGE("Unable to set up inet client on host port %u: %s", *forwardResult->hostPort(),
+ statusToString(status).c_str());
+ return nullptr;
+ }
+ auto binder = rpcSession->getRootObject();
+ if (binder == nullptr) {
+ ALOGE("RpcSession::getRootObject returns nullptr");
+ return nullptr;
+ }
+
+ LOG_ALWAYS_FATAL_IF(
+ nullptr !=
+ binder->attachObject(kDeviceServiceExtraId,
+ static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
+ &cleanupCommandResult));
+ return binder;
+}
+
+} // namespace android
diff --git a/libs/binder/ServiceManagerHost.h b/libs/binder/ServiceManagerHost.h
new file mode 100644
index 0000000..c5310da
--- /dev/null
+++ b/libs/binder/ServiceManagerHost.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <android-base/macros.h>
+#include <android/os/IServiceManager.h>
+
+namespace android {
+
+struct RpcDelegateServiceManagerOptions;
+
+// Get a service on device by running servicedispatcher with the given args, e.g.
+// getDeviceService({"foo"});
+// Return nullptr on any error.
+// When the returned binder object is destroyed, remove adb forwarding and kills
+// the long-running servicedispatcher process.
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs,
+ const RpcDelegateServiceManagerOptions& options);
+
+} // namespace android
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index f12ef4e..2d05fb2 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -23,21 +23,6 @@
namespace android {
namespace internal {
-// the libbinder parcel format is currently unstable
-
-// oldest version which is supported
-constexpr uint8_t kBinderWireFormatOldest = 1;
-// current version
-constexpr uint8_t kBinderWireFormatVersion = 1;
-
-Stability::Category Stability::Category::currentFromLevel(Level level) {
- return {
- .version = kBinderWireFormatVersion,
- .reserved = {0},
- .level = level,
- };
-}
-
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
@@ -45,8 +30,7 @@
// 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);
+ status_t result = setRepr(binder.get(), level, REPR_LOG | REPR_ALLOW_DOWNGRADE);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
@@ -62,41 +46,31 @@
forceDowngradeToStability(binder, Level::VENDOR);
}
-std::string Stability::Category::debugString() {
- return levelString(level) + " wire protocol version "
- + std::to_string(version);
-}
-
void Stability::markCompilationUnit(IBinder* binder) {
- auto stability = Category::currentFromLevel(getLocalLevel());
- status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+ status_t result = setRepr(binder, getLocalLevel(), 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(), REPR_LOG);
+ status_t result = setRepr(binder, Level::VINTF, REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
-void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) {
- auto stability = getCategory(binder.get());
- ALOGE("%s: stability is %s", tag.c_str(), stability.debugString().c_str());
+std::string Stability::debugToString(const sp<IBinder>& binder) {
+ return levelString(getRepr(binder.get()));
}
void Stability::markVndk(IBinder* binder) {
- auto stability = Category::currentFromLevel(Level::VENDOR);
- status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+ status_t result = setRepr(binder, Level::VENDOR, REPR_LOG);
LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
}
bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) {
- return check(getCategory(binder.get()), Level::VINTF);
+ return check(getRepr(binder.get()), Level::VINTF);
}
void Stability::tryMarkCompilationUnit(IBinder* binder) {
- auto stability = Category::currentFromLevel(getLocalLevel());
- (void) setRepr(binder, stability.repr(), REPR_NONE);
+ (void)setRepr(binder, getLocalLevel(), REPR_NONE);
}
Stability::Level Stability::getLocalLevel() {
@@ -112,92 +86,77 @@
#endif
}
-status_t Stability::setRepr(IBinder* binder, int32_t representation, uint32_t flags) {
+status_t Stability::setRepr(IBinder* binder, int32_t setting, uint32_t flags) {
bool log = flags & REPR_LOG;
bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE;
- auto current = getCategory(binder);
- auto setting = Category::fromRepr(representation);
-
- // If we have ahold of a binder with a newer declared version, then it
- // should support older versions, and we will simply write our parcels with
- // the current wire parcel format.
- if (setting.version < kBinderWireFormatOldest) {
- // always log, because this shouldn't happen
- ALOGE("Cannot accept binder with older binder wire protocol version "
- "%u. Versions less than %u are unsupported.", setting.version,
- kBinderWireFormatOldest);
- return BAD_TYPE;
- }
+ int16_t current = getRepr(binder);
// null binder is always written w/ 'UNDECLARED' stability
if (binder == nullptr) {
- if (setting.level == UNDECLARED) {
+ if (setting == UNDECLARED) {
return OK;
} else {
if (log) {
- ALOGE("Null binder written with stability %s.",
- levelString(setting.level).c_str());
+ ALOGE("Null binder written with stability %s.", levelString(setting).c_str());
}
return BAD_TYPE;
}
}
- if (!isDeclaredLevel(setting.level)) {
+ if (!isDeclaredLevel(setting)) {
if (log) {
- ALOGE("Can only set known stability, not %u.", setting.level);
+ ALOGE("Can only set known stability, not %d.", setting);
}
return BAD_TYPE;
}
+ Level levelSetting = static_cast<Level>(setting);
if (current == setting) return OK;
- bool hasAlreadyBeenSet = current.repr() != 0;
- bool isAllowedDowngrade = allowDowngrade && check(current, setting.level);
+ bool hasAlreadyBeenSet = current != Level::UNDECLARED;
+ bool isAllowedDowngrade = allowDowngrade && check(current, levelSetting);
if (hasAlreadyBeenSet && !isAllowedDowngrade) {
if (log) {
ALOGE("Interface being set with %s but it is already marked as %s",
- setting.debugString().c_str(),
- current.debugString().c_str());
+ levelString(setting).c_str(), levelString(current).c_str());
}
return BAD_TYPE;
}
if (isAllowedDowngrade) {
- ALOGI("Interface set with %s downgraded to %s stability",
- current.debugString().c_str(),
- setting.debugString().c_str());
+ ALOGI("Interface set with %s downgraded to %s stability", levelString(current).c_str(),
+ levelString(setting).c_str());
}
BBinder* local = binder->localBinder();
if (local != nullptr) {
- local->mStability = setting.repr();
+ local->mStability = setting;
} else {
- binder->remoteBinder()->mStability = setting.repr();
+ binder->remoteBinder()->mStability = setting;
}
return OK;
}
-Stability::Category Stability::getCategory(IBinder* binder) {
+int16_t Stability::getRepr(IBinder* binder) {
if (binder == nullptr) {
- return Category::currentFromLevel(Level::UNDECLARED);
+ return Level::UNDECLARED;
}
BBinder* local = binder->localBinder();
if (local != nullptr) {
- return Category::fromRepr(local->mStability);
+ return local->mStability;
}
- return Category::fromRepr(binder->remoteBinder()->mStability);
+ return binder->remoteBinder()->mStability;
}
-bool Stability::check(Category provided, Level required) {
- bool stable = (provided.level & required) == required;
+bool Stability::check(int16_t provided, Level required) {
+ bool stable = (provided & required) == required;
- if (provided.level != UNDECLARED && !isDeclaredLevel(provided.level)) {
- ALOGE("Unknown stability when checking interface stability %d.",
- provided.level);
+ if (provided != UNDECLARED && !isDeclaredLevel(provided)) {
+ ALOGE("Unknown stability when checking interface stability %d.", provided);
stable = false;
}
@@ -205,11 +164,11 @@
return stable;
}
-bool Stability::isDeclaredLevel(Level stability) {
+bool Stability::isDeclaredLevel(int32_t stability) {
return stability == VENDOR || stability == SYSTEM || stability == VINTF;
}
-std::string Stability::levelString(Level level) {
+std::string Stability::levelString(int32_t level) {
switch (level) {
case Level::UNDECLARED: return "undeclared stability";
case Level::VENDOR: return "vendor stability";
diff --git a/libs/binder/Static.h b/libs/binder/Static.h
index 83524e8..8444fe7 100644
--- a/libs/binder/Static.h
+++ b/libs/binder/Static.h
@@ -17,8 +17,6 @@
// All static variables go here, to control initialization and
// destruction order in the library.
-#include <utils/threads.h>
-
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index b5a078c..83b97d0 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -130,13 +130,13 @@
}
// The remote threw an exception. Get the message back.
- String16 message;
+ std::optional<String16> message;
status = parcel.readString16(&message);
if (status != OK) {
setFromStatusT(status);
return status;
}
- mMessage = String8(message);
+ mMessage = String8(message.value_or(String16()));
// Skip over the remote stack trace data
int32_t remote_stack_trace_header_size;
@@ -211,6 +211,12 @@
return status;
}
+status_t Status::writeOverParcel(Parcel* parcel) const {
+ parcel->setDataSize(0);
+ parcel->setDataPosition(0);
+ return writeToParcel(parcel);
+}
+
void Status::setException(int32_t ex, const String8& message) {
mException = ex;
mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index b9f4502..ebb0d27 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -16,18 +16,30 @@
"name": "binderDriverInterfaceTest"
},
{
+ "name": "binderHostDeviceTest"
+ },
+ {
"name": "binderTextOutputTest"
},
{
- "name": "binderParcelTest"
+ "name": "binderUnitTest"
},
{
"name": "binderLibTest"
},
{
+ "name": "binderRpcTest"
+ },
+ {
"name": "binderStabilityTest"
},
{
+ "name": "binderRpcWireProtocolTest"
+ },
+ {
+ "name": "binderUtilsHostTest"
+ },
+ {
"name": "libbinder_ndk_unit_test"
},
{
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index 90a4502..d2a5be1 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -18,10 +18,24 @@
#include <string.h>
+using android::base::ErrnoError;
+using android::base::Result;
+
namespace android {
void zeroMemory(uint8_t* data, size_t size) {
memset(data, 0, size);
}
-} // namespace android
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+ int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
+ if (flags == -1) {
+ return ErrnoError() << "Could not get flags for fd";
+ }
+ if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
+ return ErrnoError() << "Could not set non-blocking flag for fd";
+ }
+ return {};
+}
+
+} // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index f94b158..ff2fad88 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -17,9 +17,23 @@
#include <cstdint>
#include <stddef.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <log/log.h>
+
+#define TEST_AND_RETURN(value, expr) \
+ do { \
+ if (!(expr)) { \
+ ALOGE("Failed to call: %s", #expr); \
+ return value; \
+ } \
+ } while (0)
+
namespace android {
// avoid optimizations
void zeroMemory(uint8_t* data, size_t size);
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
} // namespace android
diff --git a/libs/binder/UtilsHost.cpp b/libs/binder/UtilsHost.cpp
new file mode 100644
index 0000000..52b8f69
--- /dev/null
+++ b/libs/binder/UtilsHost.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 "UtilsHost.h"
+
+#include <poll.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <sstream>
+
+#include <log/log.h>
+
+namespace android {
+
+CommandResult::~CommandResult() {
+ if (!pid.has_value()) return;
+ if (*pid == 0) {
+ ALOGW("%s: PID is unexpectedly 0, won't kill it", __PRETTY_FUNCTION__);
+ return;
+ }
+
+ ALOGE_IF(kill(*pid, SIGKILL) != 0, "kill(%d): %s", *pid, strerror(errno));
+
+ while (pid.has_value()) {
+ int status;
+ LOG_HOST("%s: Waiting for PID %d to exit.", __PRETTY_FUNCTION__, *pid);
+ int waitres = waitpid(*pid, &status, 0);
+ if (waitres == -1) {
+ ALOGE("%s: waitpid(%d): %s", __PRETTY_FUNCTION__, *pid, strerror(errno));
+ break;
+ }
+ if (WIFEXITED(status)) {
+ LOG_HOST("%s: PID %d exited.", __PRETTY_FUNCTION__, *pid);
+ pid.reset();
+ } else if (WIFSIGNALED(status)) {
+ LOG_HOST("%s: PID %d terminated by signal %d.", __PRETTY_FUNCTION__, *pid,
+ WTERMSIG(status));
+ pid.reset();
+ } else if (WIFSTOPPED(status)) {
+ ALOGW("%s: pid %d stopped", __PRETTY_FUNCTION__, *pid);
+ } else if (WIFCONTINUED(status)) {
+ ALOGW("%s: pid %d continued", __PRETTY_FUNCTION__, *pid);
+ }
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const CommandResult& res) {
+ if (res.exitCode) os << "code=" << *res.exitCode;
+ if (res.signal) os << "signal=" << *res.signal;
+ if (res.pid) os << ", pid=" << *res.pid;
+ return os << ", stdout=" << res.stdoutStr << ", stderr=" << res.stderrStr;
+}
+
+std::string CommandResult::toString() const {
+ std::stringstream ss;
+ ss << (*this);
+ return ss.str();
+}
+
+android::base::Result<CommandResult> execute(std::vector<std::string> argStringVec,
+ const std::function<bool(const CommandResult&)>& end) {
+ // turn vector<string> into null-terminated char* vector.
+ std::vector<char*> argv;
+ argv.reserve(argStringVec.size() + 1);
+ for (auto& arg : argStringVec) argv.push_back(arg.data());
+ argv.push_back(nullptr);
+
+ CommandResult ret;
+ android::base::unique_fd outWrite;
+ if (!android::base::Pipe(&ret.outPipe, &outWrite))
+ return android::base::ErrnoError() << "pipe() for outPipe";
+ android::base::unique_fd errWrite;
+ if (!android::base::Pipe(&ret.errPipe, &errWrite))
+ return android::base::ErrnoError() << "pipe() for errPipe";
+
+ int pid = fork();
+ if (pid == -1) return android::base::ErrnoError() << "fork()";
+ if (pid == 0) {
+ // child
+ ret.outPipe.reset();
+ ret.errPipe.reset();
+
+ int res = TEMP_FAILURE_RETRY(dup2(outWrite.get(), STDOUT_FILENO));
+ LOG_ALWAYS_FATAL_IF(-1 == res, "dup2(outPipe): %s", strerror(errno));
+ outWrite.reset();
+
+ res = TEMP_FAILURE_RETRY(dup2(errWrite.get(), STDERR_FILENO));
+ LOG_ALWAYS_FATAL_IF(-1 == res, "dup2(errPipe): %s", strerror(errno));
+ errWrite.reset();
+
+ execvp(argv[0], argv.data());
+ LOG_ALWAYS_FATAL("execvp() returns");
+ }
+ // parent
+ outWrite.reset();
+ errWrite.reset();
+ ret.pid = pid;
+
+ auto handlePoll = [](android::base::unique_fd* fd, const pollfd* pfd, std::string* s) {
+ if (!fd->ok()) return true;
+ if (pfd->revents & POLLIN) {
+ char buf[1024];
+ ssize_t n = TEMP_FAILURE_RETRY(read(fd->get(), buf, sizeof(buf)));
+ if (n < 0) return false;
+ if (n > 0) *s += std::string_view(buf, n);
+ }
+ if (pfd->revents & POLLHUP) {
+ fd->reset();
+ }
+ return true;
+ };
+
+ // Drain both stdout and stderr. Check end() regularly until both are closed.
+ while (ret.outPipe.ok() || ret.errPipe.ok()) {
+ pollfd fds[2];
+ pollfd *outPollFd = nullptr, *errPollFd = nullptr;
+ memset(fds, 0, sizeof(fds));
+ nfds_t nfds = 0;
+ if (ret.outPipe.ok()) {
+ outPollFd = &fds[nfds++];
+ *outPollFd = {.fd = ret.outPipe.get(), .events = POLLIN};
+ }
+ if (ret.errPipe.ok()) {
+ errPollFd = &fds[nfds++];
+ *errPollFd = {.fd = ret.errPipe.get(), .events = POLLIN};
+ }
+ int pollRet = poll(fds, nfds, 1000 /* ms timeout */);
+ if (pollRet == -1) return android::base::ErrnoError() << "poll()";
+
+ if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdoutStr))
+ return android::base::ErrnoError() << "read(stdout)";
+ if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderrStr))
+ return android::base::ErrnoError() << "read(stderr)";
+
+ if (end && end(ret)) return ret;
+ }
+
+ // If both stdout and stderr are closed by the subprocess, it may or may not be terminated.
+ while (ret.pid.has_value()) {
+ int status;
+ auto exitPid = waitpid(pid, &status, 0);
+ if (exitPid == -1) return android::base::ErrnoError() << "waitpid(" << pid << ")";
+ if (exitPid == pid) {
+ if (WIFEXITED(status)) {
+ ret.pid = std::nullopt;
+ ret.exitCode = WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ ret.pid = std::nullopt;
+ ret.signal = WTERMSIG(status);
+ } else if (WIFSTOPPED(status)) {
+ ALOGW("%s: pid %d stopped", __PRETTY_FUNCTION__, *ret.pid);
+ } else if (WIFCONTINUED(status)) {
+ ALOGW("%s: pid %d continued", __PRETTY_FUNCTION__, *ret.pid);
+ }
+ }
+ // ret is not changed unless the process is terminated (where pid == nullopt). Hence there
+ // is no need to check the predicate `end(ret)`.
+ }
+
+ return ret;
+}
+} // namespace android
diff --git a/libs/binder/UtilsHost.h b/libs/binder/UtilsHost.h
new file mode 100644
index 0000000..98ac4e0
--- /dev/null
+++ b/libs/binder/UtilsHost.h
@@ -0,0 +1,99 @@
+/*
+ * 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 <optional>
+#include <ostream>
+#include <string>
+#include <variant>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+
+/**
+ * Log a lot more information about host-device binder communication, when debugging issues.
+ */
+#define SHOULD_LOG_HOST false
+
+#if SHOULD_LOG_HOST
+#define LOG_HOST(...) ALOGI(__VA_ARGS__)
+#else
+#define LOG_HOST(...) ALOGV(__VA_ARGS__) // for type checking
+#endif
+
+namespace android {
+
+struct CommandResult {
+ std::optional<int32_t> exitCode;
+ std::optional<int32_t> signal;
+ std::optional<pid_t> pid;
+ std::string stdoutStr;
+ std::string stderrStr;
+
+ android::base::unique_fd outPipe;
+ android::base::unique_fd errPipe;
+
+ CommandResult() = default;
+ CommandResult(CommandResult&& other) noexcept { (*this) = std::move(other); }
+ CommandResult& operator=(CommandResult&& other) noexcept {
+ std::swap(exitCode, other.exitCode);
+ std::swap(signal, other.signal);
+ std::swap(pid, other.pid);
+ std::swap(stdoutStr, other.stdoutStr);
+ std::swap(stderrStr, other.stderrStr);
+ return *this;
+ }
+ ~CommandResult();
+ [[nodiscard]] std::string toString() const;
+
+ [[nodiscard]] bool stdoutEndsWithNewLine() const {
+ return !stdoutStr.empty() && stdoutStr.back() == '\n';
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(CommandResult);
+};
+
+std::ostream& operator<<(std::ostream& os, const CommandResult& res);
+
+// Execute a command using tokens specified in @a argStringVec.
+//
+// @a end is a predicate checked periodically when the command emits any output to stdout or
+// stderr. When it is evaluated to true, the function returns immediately even though
+// the child process has not been terminated. The function also assumes that, after @a end
+// is evaluated to true, the child process does not emit any other messages.
+// If this is not the case, caller to execute() must handle these I/O in the pipes in the returned
+// CommandResult object. Otherwise the child program may hang on I/O.
+//
+// If @a end is nullptr, it is equivalent to a predicate that always returns false. In this
+// case, execute() returns after the child process is terminated.
+//
+// If @a end is evaluated to true, and execute() returns with the child process running,
+// the returned CommandResult has pid, outPipe, and errPipe set. In this case, the caller is
+// responsible for holding the returned CommandResult. When the CommandResult object is destroyed,
+// the child process is killed.
+//
+// On the other hand, execute() returns with the child process terminated, either exitCode or signal
+// is set.
+//
+// If the parent process has encountered any errors for system calls, return ExecuteError with
+// the proper errno set.
+android::base::Result<CommandResult> execute(std::vector<std::string> argStringVec,
+ const std::function<bool(const CommandResult&)>& end);
+} // namespace android
diff --git a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
new file mode 100644
index 0000000..75f8753
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 android.content.pm;
+
+/**
+ * This event is designed for notification to native code listener about
+ * any changes to set of apex packages staged for installation on next boot.
+ *
+ * @hide
+ */
+parcelable ApexStagedEvent {
+ @utf8InCpp String[] stagedApexModuleNames;
+}
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index c20d9f6..7c99f76 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -18,6 +18,8 @@
package android.content.pm;
import android.content.pm.IPackageChangeObserver;
+import android.content.pm.IStagedApexObserver;
+import android.content.pm.StagedApexInfo;
/**
* Parallel implementation of certain {@link PackageManager} APIs that need to
@@ -123,4 +125,24 @@
* requested version.
*/
boolean hasSystemFeature(in String featureName, in int version);
+
+ /** Register a observer for change in set of staged APEX ready for installation */
+ void registerStagedApexObserver(in IStagedApexObserver observer);
+
+ /**
+ * Unregister an existing staged apex observer.
+ * This does nothing if this observer was not already registered.
+ */
+ void unregisterStagedApexObserver(in IStagedApexObserver observer);
+
+ /**
+ * Get APEX module names of all APEX that are staged ready for installation
+ */
+ @utf8InCpp String[] getStagedApexModuleNames();
+
+ /**
+ * Get information of APEX which is staged ready for installation.
+ * Returns null if no such APEX is found.
+ */
+ @nullable StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
}
diff --git a/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
new file mode 100644
index 0000000..9906436
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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 android.content.pm;
+
+import android.content.pm.ApexStagedEvent;
+
+/**
+ * This is a non-blocking notification when set of staged apex has changed
+ *
+ * @hide
+ */
+oneway interface IStagedApexObserver {
+ void onApexStaged(in ApexStagedEvent event);
+}
diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
new file mode 100644
index 0000000..949835b
--- /dev/null
+++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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 android.content.pm;
+
+/**
+ * This object is designed for returning information regarding
+ * staged APEX that are ready to be installed on next reboot.
+ *
+ * @hide
+ */
+parcelable StagedApexInfo {
+ @utf8InCpp String moduleName;
+ @utf8InCpp String diskImagePath;
+ long versionCode;
+ @utf8InCpp String versionName;
+ boolean hasClassPathJars;
+}
diff --git a/libs/binder/aidl/android/os/ConnectionInfo.aidl b/libs/binder/aidl/android/os/ConnectionInfo.aidl
new file mode 100644
index 0000000..160c9ea
--- /dev/null
+++ b/libs/binder/aidl/android/os/ConnectionInfo.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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 android.os;
+
+/**
+ * Remote connection info associated with a declared service
+ * @hide
+ */
+parcelable ConnectionInfo {
+ /**
+ * IP address that the service is listening on.
+ */
+ @utf8InCpp String ipAddress;
+ /**
+ * Port number that the service is listening on. Actual value is an unsigned integer.
+ */
+ int port;
+}
+
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 75c4092..5880c0a 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -19,6 +19,7 @@
import android.os.IClientCallback;
import android.os.IServiceCallback;
import android.os.ServiceDebugInfo;
+import android.os.ConnectionInfo;
/**
* Basic interface for finding and publishing system services.
@@ -113,6 +114,11 @@
@nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
/**
+ * If connection info is available for the given instance, returns the ConnectionInfo
+ */
+ @nullable ConnectionInfo getConnectionInfo(@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 7e9be41..46223bb 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -54,12 +54,11 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) final;
+ virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) final;
virtual void* findObject(const void* objectID) const final;
- virtual void detachObject(const void* objectID) final;
+ virtual void* detachObject(const void* objectID) final;
+ void withLock(const std::function<void()>& doWithLock);
virtual BBinder* localBinder();
@@ -94,6 +93,16 @@
pid_t getDebugPid();
+ // Whether this binder has been sent to another process.
+ bool wasParceled();
+ // Consider this binder as parceled (setup/init-related calls should no
+ // longer by called. This is automatically set by when this binder is sent
+ // to another process.
+ void setParceled();
+
+ [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd,
+ const sp<IBinder>& keepAliveBinder);
+
protected:
virtual ~BBinder();
@@ -107,17 +116,24 @@
BBinder(const BBinder& o);
BBinder& operator=(const BBinder& o);
+ class RpcServerLink;
class Extras;
Extras* getOrCreateExtras();
+ [[nodiscard]] status_t setRpcClientDebug(const Parcel& data);
+ void removeRpcServerLink(const sp<RpcServerLink>& link);
+
std::atomic<Extras*> mExtras;
friend ::android::internal::Stability;
- union {
- int32_t mStability;
- void* mReserved0;
- };
+ int16_t mStability;
+ bool mParceled;
+ uint8_t mReserved0;
+
+#ifdef __LP64__
+ int32_t mReserved1;
+#endif
};
// ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index 5776f3c..e58d489 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -26,6 +26,24 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+// WARNING: deprecated - DO NOT USE - prefer to setup service directly.
+//
+// This class embellishes a class with a few static methods which can be used in
+// limited circumstances (when one service needs to be registered and
+// published). However, this is an anti-pattern:
+// - these methods are aliases of existing methods, and as such, represent an
+// incremental amount of information required to understand the system but
+// which does not actually save in terms of lines of code. For instance, users
+// of this class should be surprised to know that this will start up to 16
+// threads in the binder threadpool.
+// - the template instantiation costs need to be paid, even though everything
+// done here is generic.
+// - the getServiceName API here is undocumented and non-local (for instance,
+// this unnecessarily assumes a single service type will only be instantiated
+// once with no arguments).
+//
+// So, DO NOT USE.
+
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 61bf018..19ad5e6 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,11 +17,9 @@
#pragma once
#include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
-#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
+#include <map>
#include <unordered_map>
#include <variant>
@@ -40,9 +38,6 @@
class BpBinder : public IBinder
{
public:
- static sp<BpBinder> create(int32_t handle);
- static sp<BpBinder> create(const sp<RpcSession>& session, const RpcAddress& address);
-
/**
* Return value:
* true - this is associated with a socket RpcSession
@@ -72,12 +67,11 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) final;
+ virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) final;
virtual void* findObject(const void* objectID) const final;
- virtual void detachObject(const void* objectID) final;
+ virtual void* detachObject(const void* objectID) final;
+ void withLock(const std::function<void()>& doWithLock);
virtual BpBinder* remoteBinder();
@@ -91,71 +85,76 @@
static void setLimitCallback(binder_proxy_limit_callback cb);
static void setBinderProxyCountWatermarks(int high, int low);
- class ObjectManager
- {
+ std::optional<int32_t> getDebugBinderHandle() const;
+
+ class ObjectManager {
public:
- ObjectManager();
- ~ObjectManager();
+ ObjectManager();
+ ~ObjectManager();
- void attach( const void* objectID,
- void* object,
- void* cleanupCookie,
- IBinder::object_cleanup_func func);
- void* find(const void* objectID) const;
- void detach(const void* objectID);
+ void* attach(const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func);
+ void* find(const void* objectID) const;
+ void* detach(const void* objectID);
- void kill();
+ void kill();
private:
- ObjectManager(const ObjectManager&);
+ ObjectManager(const ObjectManager&);
ObjectManager& operator=(const ObjectManager&);
- struct entry_t
- {
+ struct entry_t {
void* object;
void* cleanupCookie;
IBinder::object_cleanup_func func;
};
- KeyedVector<const void*, entry_t> mObjects;
+ std::map<const void*, entry_t> mObjects;
};
- class PrivateAccessorForId {
+ class PrivateAccessor {
private:
friend class BpBinder;
friend class ::android::Parcel;
friend class ::android::ProcessState;
+ friend class ::android::RpcSession;
friend class ::android::RpcState;
- explicit PrivateAccessorForId(const BpBinder* binder) : mBinder(binder) {}
+ explicit PrivateAccessor(const BpBinder* binder) : mBinder(binder) {}
+
+ static sp<BpBinder> create(int32_t handle) { return BpBinder::create(handle); }
+ static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address) {
+ return BpBinder::create(session, address);
+ }
// valid if !isRpcBinder
int32_t binderHandle() const { return mBinder->binderHandle(); }
// valid if isRpcBinder
- const RpcAddress& rpcAddress() const { return mBinder->rpcAddress(); }
+ uint64_t rpcAddress() const { return mBinder->rpcAddress(); }
const sp<RpcSession>& rpcSession() const { return mBinder->rpcSession(); }
const BpBinder* mBinder;
};
- const PrivateAccessorForId getPrivateAccessorForId() const {
- return PrivateAccessorForId(this);
- }
+ const PrivateAccessor getPrivateAccessor() const { return PrivateAccessor(this); }
private:
- friend PrivateAccessorForId;
+ friend PrivateAccessor;
friend class sp<BpBinder>;
+ static sp<BpBinder> create(int32_t handle);
+ static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address);
+
struct BinderHandle {
int32_t handle;
};
struct RpcHandle {
sp<RpcSession> session;
- RpcAddress address;
+ uint64_t address;
};
using Handle = std::variant<BinderHandle, RpcHandle>;
int32_t binderHandle() const;
- const RpcAddress& rpcAddress() const;
+ uint64_t rpcAddress() const;
const sp<RpcSession>& rpcSession() const;
explicit BpBinder(Handle&& handle);
@@ -197,6 +196,7 @@
static uint32_t sBinderProxyCountHighWatermark;
static uint32_t sBinderProxyCountLowWatermark;
static bool sBinderProxyThrottleCreate;
+ static std::unordered_map<int32_t,uint32_t> sLastLimitCallbackMap;
};
} // namespace android
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 97c826c..43fc5ff 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -22,6 +22,8 @@
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <functional>
+
// linux/binder.h defines this, but we don't want to include it here in order to
// avoid exporting the kernel headers
#ifndef B_PACK_CHARS
@@ -60,6 +62,7 @@
SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'),
DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'),
+ SET_RPC_CLIENT_TRANSACTION = B_PACK_CHARS('_', 'R', 'P', 'C'),
// See android.os.IBinder.TWEET_TRANSACTION
// Most importantly, messages can be anything not exceeding 130 UTF-8
@@ -152,6 +155,27 @@
*/
status_t getDebugPid(pid_t* outPid);
+ /**
+ * Set the RPC client fd to this binder service, for debugging. This is only available on
+ * debuggable builds.
+ *
+ * When this is called on a binder service, the service:
+ * 1. sets up RPC server
+ * 2. spawns 1 new thread that calls RpcServer::join()
+ * - join() spawns some number of threads that accept() connections; see RpcServer
+ *
+ * setRpcClientDebug() may be called multiple times. Each call will add a new RpcServer
+ * and opens up a TCP port.
+ *
+ * Note: A thread is spawned for each accept()'ed fd, which may call into functions of the
+ * interface freely. See RpcServer::join(). To avoid such race conditions, implement the service
+ * functions with multithreading support.
+ *
+ * On death of @a keepAliveBinder, the RpcServer shuts down.
+ */
+ [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd socketFd,
+ const sp<IBinder>& keepAliveBinder);
+
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
@@ -233,26 +257,30 @@
* objects are invoked with their respective objectID, object, and
* cleanupCookie. Access to these APIs can be made from multiple threads,
* but calls from different threads are allowed to be interleaved.
+ *
+ * This returns the object which is already attached. If this returns a
+ * non-null value, it means that attachObject failed (a given objectID can
+ * only be used once).
*/
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) = 0;
+ [[nodiscard]] virtual void* attachObject(const void* objectID, void* object,
+ void* cleanupCookie, object_cleanup_func func) = 0;
/**
* Returns object attached with attachObject.
*/
- virtual void* findObject(const void* objectID) const = 0;
+ [[nodiscard]] virtual void* findObject(const void* objectID) const = 0;
/**
- * WARNING: this API does not call the cleanup function for legacy reasons.
- * It also does not return void* for legacy reasons. If you need to detach
- * an object and destroy it, there are two options:
- * - if you can, don't call detachObject and instead wait for the destructor
- * to clean it up.
- * - manually retrieve and destruct the object (if multiple of your threads
- * are accessing these APIs, you must guarantee that attachObject isn't
- * called after findObject and before detachObject is called).
+ * Returns object attached with attachObject, and detaches it. This does not
+ * delete the object.
*/
- virtual void detachObject(const void* objectID) = 0;
+ [[nodiscard]] virtual void* detachObject(const void* objectID) = 0;
+
+ /**
+ * Use the lock that this binder contains internally. For instance, this can
+ * be used to modify an attached object without needing to add an additional
+ * lock (though, that attached object must be retrieved before calling this
+ * method). Calling (most) IBinder methods inside this will deadlock.
+ */
+ void withLock(const std::function<void()>& doWithLock);
virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index ff90b30..f295417 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -93,20 +93,20 @@
// ----------------------------------------------------------------------
-#define DECLARE_META_INTERFACE(INTERFACE) \
-public: \
- static const ::android::String16 descriptor; \
- static ::android::sp<I##INTERFACE> asInterface( \
- const ::android::sp<::android::IBinder>& obj); \
- virtual const ::android::String16& getInterfaceDescriptor() const; \
- I##INTERFACE(); \
- virtual ~I##INTERFACE(); \
- static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl); \
- static const std::unique_ptr<I##INTERFACE>& getDefaultImpl(); \
-private: \
- static std::unique_ptr<I##INTERFACE> default_impl; \
-public: \
-
+#define DECLARE_META_INTERFACE(INTERFACE) \
+public: \
+ static const ::android::String16 descriptor; \
+ static ::android::sp<I##INTERFACE> asInterface(const ::android::sp<::android::IBinder>& obj); \
+ virtual const ::android::String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+ static bool setDefaultImpl(::android::sp<I##INTERFACE> impl); \
+ static const ::android::sp<I##INTERFACE>& getDefaultImpl(); \
+ \
+private: \
+ static ::android::sp<I##INTERFACE> default_impl; \
+ \
+public:
#define __IINTF_CONCAT(x, y) (x ## y)
@@ -129,48 +129,50 @@
#endif
-#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\
- const ::android::StaticString16 \
- I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
- const ::android::String16 I##INTERFACE::descriptor( \
- I##INTERFACE##_descriptor_static_str16); \
- const ::android::String16& \
- I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
- const ::android::sp<::android::IBinder>& obj) \
- { \
- ::android::sp<I##INTERFACE> intr; \
- if (obj != nullptr) { \
- intr = ::android::sp<I##INTERFACE>::cast( \
- obj->queryLocalInterface(I##INTERFACE::descriptor)); \
- if (intr == nullptr) { \
- intr = ::android::sp<Bp##INTERFACE>::make(obj); \
- } \
- } \
- return intr; \
- } \
- std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl; \
- bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
- { \
- /* Only one user of this interface can use this function */ \
- /* at a time. This is a heuristic to detect if two different */ \
- /* users in the same process use this function. */ \
- assert(!I##INTERFACE::default_impl); \
- if (impl) { \
- I##INTERFACE::default_impl = std::move(impl); \
- return true; \
- } \
- return false; \
- } \
- const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
- { \
- return I##INTERFACE::default_impl; \
- } \
- I##INTERFACE::I##INTERFACE() { } \
- I##INTERFACE::~I##INTERFACE() { } \
+// Macro to be used by both IMPLEMENT_META_INTERFACE and IMPLEMENT_META_NESTED_INTERFACE
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE) \
+ const ::android::String16& ITYPE::getInterfaceDescriptor() const { return ITYPE::descriptor; } \
+ ::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) { \
+ ::android::sp<ITYPE> intr; \
+ if (obj != nullptr) { \
+ intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor)); \
+ if (intr == nullptr) { \
+ intr = ::android::sp<BPTYPE>::make(obj); \
+ } \
+ } \
+ return intr; \
+ } \
+ ::android::sp<ITYPE> ITYPE::default_impl; \
+ bool ITYPE::setDefaultImpl(::android::sp<ITYPE> impl) { \
+ /* Only one user of this interface can use this function */ \
+ /* at a time. This is a heuristic to detect if two different */ \
+ /* users in the same process use this function. */ \
+ assert(!ITYPE::default_impl); \
+ if (impl) { \
+ ITYPE::default_impl = std::move(impl); \
+ return true; \
+ } \
+ return false; \
+ } \
+ const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
+ ITYPE::INAME() {} \
+ ITYPE::~INAME() {}
+// Macro for an interface type.
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
+ const ::android::StaticString16 I##INTERFACE##_descriptor_static_str16( \
+ __IINTF_CONCAT(u, NAME)); \
+ const ::android::String16 I##INTERFACE::descriptor(I##INTERFACE##_descriptor_static_str16); \
+ DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(I##INTERFACE, I##INTERFACE, Bp##INTERFACE)
+
+// Macro for "nested" interface type.
+// For example,
+// class Parent .. { class INested .. { }; };
+// DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(Parent, Nested, "Parent.INested")
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(PARENT, INTERFACE, NAME) \
+ const ::android::String16 PARENT::I##INTERFACE::descriptor(NAME); \
+ DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(PARENT::I##INTERFACE, I##INTERFACE, \
+ PARENT::Bp##INTERFACE)
#define CHECK_INTERFACE(interface, data, reply) \
do { \
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index b401ea9..bf02099 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -51,17 +51,9 @@
static status_t freeze(pid_t pid, bool enabled, uint32_t timeout_ms);
// Provide information about the state of a frozen process
- static status_t getProcessFreezeInfo(pid_t pid, bool *sync_received,
- bool *async_received);
-
- // TODO: Remove the above legacy duplicated function in next version
-#ifndef __ANDROID_VNDK__
static status_t getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
uint32_t *async_received);
-#endif
- sp<ProcessState> process();
-
status_t clearLastError();
/**
@@ -69,7 +61,7 @@
* call. If not in a binder call, this will return getpid. If the
* call is oneway, this will return 0.
*/
- pid_t getCallingPid() const;
+ [[nodiscard]] pid_t getCallingPid() const;
/**
* Returns the SELinux security identifier of the process which has
@@ -80,13 +72,43 @@
* This can't be restored once it's cleared, and it does not return the
* context of the current process when not in a binder call.
*/
- const char* getCallingSid() const;
+ [[nodiscard]] const char* getCallingSid() const;
/**
* Returns the UID of the process which has made the current binder
* call. If not in a binder call, this will return 0.
*/
- uid_t getCallingUid() const;
+ [[nodiscard]] uid_t getCallingUid() const;
+
+ /**
+ * Make it an abort to rely on getCalling* for a section of
+ * execution.
+ *
+ * Usage:
+ * IPCThreadState::SpGuard guard {
+ * .address = __builtin_frame_address(0),
+ * .context = "...",
+ * };
+ * const auto* orig = pushGetCallingSpGuard(&guard);
+ * {
+ * // will abort if you call getCalling*, unless you are
+ * // serving a nested binder transaction
+ * }
+ * restoreCallingSpGuard(orig);
+ */
+ struct SpGuard {
+ const void* address;
+ const char* context;
+ };
+ const SpGuard* pushGetCallingSpGuard(const SpGuard* guard);
+ void restoreGetCallingSpGuard(const SpGuard* guard);
+ /**
+ * Used internally by getCalling*. Can also be used to assert that
+ * you are in a binder context (getCalling* is valid). This is
+ * intentionally not exposed as a boolean API since code should be
+ * written to know its environment.
+ */
+ void checkContextIsBinderForUse(const char* use) const;
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
@@ -204,6 +226,7 @@
Parcel mOut;
status_t mLastError;
const void* mServingStackPointer;
+ const SpGuard* mServingStackPointerGuard;
pid_t mCallingPid;
const char* mCallingSid;
uid_t mCallingUid;
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3dbe2c4..bb55831 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -15,11 +15,9 @@
*/
#pragma once
-
#include <binder/IInterface.h>
#include <utils/Vector.h>
#include <utils/String16.h>
-
#include <optional>
namespace android {
@@ -58,8 +56,16 @@
static const int DUMP_FLAG_PROTO = 1 << 4;
/**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
+ * Retrieve an existing service, blocking for a few seconds if it doesn't yet exist. This
+ * does polling. A more efficient way to make sure you unblock as soon as the service is
+ * available is to use waitForService or to use service notifications.
+ *
+ * Warning: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with isDeclared).
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
@@ -107,6 +113,27 @@
* this can be updated.
*/
virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
+
+ /**
+ * If this instance has declared remote connection information, returns
+ * the ConnectionInfo.
+ */
+ struct ConnectionInfo {
+ std::string ipAddress;
+ unsigned int port;
+ };
+ virtual std::optional<ConnectionInfo> getConnectionInfo(const String16& name) = 0;
+
+ struct LocalRegistrationCallback : public virtual RefBase {
+ virtual void onServiceRegistration(const String16& instance, const sp<IBinder>& binder) = 0;
+ virtual ~LocalRegistrationCallback() {}
+ };
+
+ virtual status_t registerForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) = 0;
+
+ virtual status_t unregisterForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) = 0;
};
sp<IServiceManager> defaultServiceManager();
@@ -167,6 +194,29 @@
bool checkCallingPermission(const String16& permission);
bool checkCallingPermission(const String16& permission,
int32_t* outPid, int32_t* outUid);
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid,
+ bool logPermissionFailure = true);
+
+#ifndef __ANDROID__
+// Create an IServiceManager that delegates the service manager on the device via adb.
+// This is can be set as the default service manager at program start, so that
+// defaultServiceManager() returns it:
+// int main() {
+// setDefaultServiceManager(createRpcDelegateServiceManager());
+// auto sm = defaultServiceManager();
+// // ...
+// }
+// Resources are cleaned up when the object is destroyed.
+//
+// For each returned binder object, at most |maxOutgoingThreads| outgoing threads are instantiated.
+// Hence, only |maxOutgoingThreads| calls can be made simultaneously. Additional calls are blocked
+// if there are |maxOutgoingThreads| ongoing calls. See RpcSession::setMaxOutgoingThreads.
+// If |maxOutgoingThreads| is not set, default is |RpcSession::kDefaultMaxOutgoingThreads|.
+struct RpcDelegateServiceManagerOptions {
+ std::optional<size_t> maxOutgoingThreads;
+};
+sp<IServiceManager> createRpcDelegateServiceManager(
+ const RpcDelegateServiceManagerOptions& options);
+#endif
} // namespace android
diff --git a/libs/binder/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h
index e727772..3f7dd11 100644
--- a/libs/binder/include/binder/MemoryDealer.h
+++ b/libs/binder/include/binder/MemoryDealer.h
@@ -36,7 +36,6 @@
uint32_t flags = 0 /* or bits such as MemoryHeapBase::READ_ONLY */ );
virtual sp<IMemory> allocate(size_t size);
- virtual void deallocate(size_t offset);
virtual void dump(const char* what) const;
// allocations are aligned to some value. return that value so clients can account for it.
@@ -48,6 +47,8 @@
virtual ~MemoryDealer();
private:
+ friend class Allocation;
+ virtual void deallocate(size_t offset);
const sp<IMemoryHeap>& heap() const;
SimpleBestFitAllocator* allocator() const;
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index dd76943..15dd28f 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -34,7 +34,21 @@
// memory won't be mapped locally, but will be mapped in the remote
// process.
DONT_MAP_LOCALLY = 0x00000100,
- NO_CACHING = 0x00000200
+ NO_CACHING = 0x00000200,
+ // Bypass ashmem-libcutils to create a memfd shared region.
+ // Ashmem-libcutils will eventually migrate to memfd.
+ // Memfd has security benefits and supports file sealing.
+ // Calling process will need to modify selinux permissions to
+ // open access to tmpfs files. See audioserver for examples.
+ // This is only valid for size constructor.
+ // For host compilation targets, memfd is stubbed in favor of /tmp
+ // files so sealing is not enforced.
+ FORCE_MEMFD = 0x00000400,
+ // Default opt-out of sealing behavior in memfd to avoid potential DOS.
+ // Clients of shared files can seal at anytime via syscall, leading to
+ // TOC/TOU issues if additional seals prevent access from the creating
+ // process. Alternatively, seccomp fcntl().
+ MEMFD_ALLOW_SEALING = 0x00000800
};
/*
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5aaaa0c..e2b2c51 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -16,6 +16,7 @@
#pragma once
+#include <array>
#include <map> // for legacy reasons
#include <string>
#include <type_traits>
@@ -53,6 +54,9 @@
class RpcSession;
class String8;
class TextOutput;
+namespace binder {
+class Status;
+}
class Parcel {
friend class IPCThreadState;
@@ -81,12 +85,21 @@
size_t start, size_t len);
int compareData(const Parcel& other);
+ status_t compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+ size_t length, int* result) const;
bool allowFds() const;
bool pushAllowFds(bool allowFds);
void restoreAllowFds(bool lastValue);
bool hasFileDescriptors() const;
+ status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
+
+ // returns all binder objects in the Parcel
+ std::vector<sp<IBinder>> debugReadAllStrongBinders() const;
+ // returns all file descriptors in the Parcel
+ // does not dup
+ std::vector<int> debugReadAllFileDescriptors() const;
// Zeros data when reallocating. Other mitigations may be added
// in the future.
@@ -127,6 +140,10 @@
IPCThreadState* threadState = nullptr) const;
bool checkInterface(IBinder*) const;
+ // Verify there are no bytes left to be read on the Parcel.
+ // Returns Status(EX_BAD_PARCELABLE) when the Parcel is not consumed.
+ binder::Status enforceNoDataAvail() const;
+
void freeData();
size_t objectsCount() const;
@@ -204,6 +221,32 @@
status_t writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead")));
status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
+ // Write an IInterface or a vector of IInterface's
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinder(const sp<T>& val) {
+ return writeStrongBinder(T::asBinder(val));
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinderVector(const std::vector<sp<T>>& val) {
+ return writeData(val);
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t writeStrongBinderVector(const std::optional<std::vector<sp<T>>>& val) {
+ return writeData(val);
+ }
+
+ template <typename T, size_t N>
+ status_t writeFixedArray(const std::array<T, N>& val) {
+ return writeData(val);
+ }
+ template <typename T, size_t N>
+ status_t writeFixedArray(const std::optional<std::array<T, N>>& val) {
+ return writeData(val);
+ }
+
// Write an Enum vector with underlying type int8_t.
// Does not use padding; each byte is contiguous.
template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
@@ -245,9 +288,10 @@
template<typename T>
status_t writeNullableParcelable(const std::optional<T>& parcelable)
{ return writeData(parcelable); }
- template<typename T>
- status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
- { return writeData(parcelable); }
+ template <typename T>
+ status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
+ return writeData(parcelable);
+ }
status_t writeParcelable(const Parcelable& parcelable);
@@ -401,9 +445,10 @@
template<typename T>
status_t readParcelable(std::optional<T>* parcelable) const
{ return readData(parcelable); }
- template<typename T>
- status_t readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
- { return readData(parcelable); }
+ template <typename T>
+ status_t readParcelable(std::unique_ptr<T>* parcelable) const {
+ return readData(parcelable);
+ }
// If strong binder would be nullptr, readStrongBinder() returns an error.
// TODO: T must be derived from IInterface, fix for clarity.
@@ -416,6 +461,16 @@
status_t readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const;
status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t readStrongBinderVector(std::vector<sp<T>>* val) const {
+ return readData(val);
+ }
+ template <typename T,
+ std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+ status_t readStrongBinderVector(std::optional<std::vector<sp<T>>>* val) const {
+ return readData(val);
+ }
status_t readByteVector(std::optional<std::vector<int8_t>>* val) const;
status_t readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
@@ -455,6 +510,15 @@
std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const __attribute__((deprecated("use std::optional version instead")));
status_t readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const;
+ template <typename T, size_t N>
+ status_t readFixedArray(std::array<T, N>* val) const {
+ return readData(val);
+ }
+ template <typename T, size_t N>
+ status_t readFixedArray(std::optional<std::array<T, N>>* val) const {
+ return readData(val);
+ }
+
template<typename T>
status_t read(Flattenable<T>& val) const;
@@ -561,6 +625,8 @@
status_t flattenBinder(const sp<IBinder>& binder);
status_t unflattenBinder(sp<IBinder>* out) const;
+ status_t readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const;
+
template<class T>
status_t readAligned(T *pArg) const;
@@ -784,6 +850,16 @@
|| is_specialization_v<T, std::unique_ptr>
|| is_specialization_v<T, std::shared_ptr>;
+ // Tells if T is a fixed-size array.
+ template <typename T>
+ struct is_fixed_array : std::false_type {};
+
+ template <typename T, size_t N>
+ struct is_fixed_array<std::array<T, N>> : std::true_type {};
+
+ template <typename T>
+ static inline constexpr bool is_fixed_array_v = is_fixed_array<T>::value;
+
// special int32 value to indicate NonNull or Null parcelables
// This is fixed to be only 0 or 1 by contract, do not change.
static constexpr int32_t kNonNullParcelableFlag = 1;
@@ -888,7 +964,9 @@
if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
} else if constexpr (std::is_base_of_v<Parcelable, T>) {
if (!c) return writeData(static_cast<int32_t>(kNullParcelableFlag));
- } else /* constexpr */ { // could define this, but raise as error.
+ } else if constexpr (is_fixed_array_v<T>) {
+ if (!c) return writeData(static_cast<int32_t>(kNullVectorSize));
+ } else /* constexpr */ { // could define this, but raise as error.
static_assert(dependent_false_v<CT>);
}
return writeData(*c);
@@ -927,6 +1005,23 @@
return OK;
}
+ template <typename T, size_t N>
+ status_t writeData(const std::array<T, N>& val) {
+ static_assert(N <= std::numeric_limits<int32_t>::max());
+ status_t status = writeData(static_cast<int32_t>(N));
+ if (status != OK) return status;
+ if constexpr (is_pointer_equivalent_array_v<T>) {
+ static_assert(N <= std::numeric_limits<size_t>::max() / sizeof(T));
+ return write(val.data(), val.size() * sizeof(T));
+ } else /* constexpr */ {
+ for (const auto& t : val) {
+ status = writeData(t);
+ if (status != OK) return status;
+ }
+ return OK;
+ }
+ }
+
// readData function overloads.
// Implementation detail: Function overloading improves code readability over
// template overloading, but prevents readData<T> from being used for those types.
@@ -1019,9 +1114,8 @@
int32_t peek;
status_t status = readData(&peek);
if (status != OK) return status;
- if constexpr (is_specialization_v<T, std::vector>
- || std::is_same_v<T, String16>
- || std::is_same_v<T, std::string>) {
+ if constexpr (is_specialization_v<T, std::vector> || is_fixed_array_v<T> ||
+ std::is_same_v<T, String16> || std::is_same_v<T, std::string>) {
if (peek == kNullVectorSize) {
c->reset();
return OK;
@@ -1031,12 +1125,15 @@
c->reset();
return OK;
}
- } else /* constexpr */ { // could define this, but raise as error.
+ } else /* constexpr */ { // could define this, but raise as error.
static_assert(dependent_false_v<CT>);
}
// create a new object.
if constexpr (is_specialization_v<CT, std::optional>) {
- c->emplace();
+ // Call default constructor explicitly
+ // - Clang bug: https://bugs.llvm.org/show_bug.cgi?id=35748
+ // std::optional::emplace() doesn't work with nested types.
+ c->emplace(T());
} else /* constexpr */ {
T* const t = new (std::nothrow) T; // contents read from Parcel below.
if (t == nullptr) return NO_MEMORY;
@@ -1045,7 +1142,7 @@
// rewind data ptr to reread (this is pretty quick), otherwise we could
// pass an optional argument to readData to indicate a peeked value.
setDataPosition(startPos);
- if constexpr (is_specialization_v<T, std::vector>) {
+ if constexpr (is_specialization_v<T, std::vector> || is_fixed_array_v<T>) {
return readData(&**c, READ_FLAG_SP_NULLABLE); // nullable sp<> allowed now
} else {
return readData(&**c);
@@ -1108,6 +1205,41 @@
return OK;
}
+ template <typename T, size_t N>
+ status_t readData(std::array<T, N>* val, ReadFlags readFlags = READ_FLAG_NONE) const {
+ static_assert(N <= std::numeric_limits<int32_t>::max());
+ int32_t size;
+ status_t status = readInt32(&size);
+ if (status != OK) return status;
+ if (size < 0) return UNEXPECTED_NULL;
+ if (size != static_cast<int32_t>(N)) return BAD_VALUE;
+ if constexpr (is_pointer_equivalent_array_v<T>) {
+ auto data = reinterpret_cast<const T*>(readInplace(N * sizeof(T)));
+ if (data == nullptr) return BAD_VALUE;
+ memcpy(val->data(), data, N * sizeof(T));
+ } else if constexpr (is_specialization_v<T, sp>) {
+ for (auto& t : *val) {
+ if (readFlags & READ_FLAG_SP_NULLABLE) {
+ status = readNullableStrongBinder(&t); // allow nullable
+ } else {
+ status = readStrongBinder(&t);
+ }
+ if (status != OK) return status;
+ }
+ } else if constexpr (is_fixed_array_v<T>) { // pass readFlags down to nested arrays
+ for (auto& t : *val) {
+ status = readData(&t, readFlags);
+ if (status != OK) return status;
+ }
+ } else /* constexpr */ {
+ for (auto& t : *val) {
+ status = readData(&t);
+ if (status != OK) return status;
+ }
+ }
+ return OK;
+ }
+
//-----------------------------------------------------------------------------
private:
@@ -1137,6 +1269,7 @@
release_func mOwner;
sp<RpcSession> mSession;
+ size_t mReserved;
class Blob {
public:
@@ -1221,13 +1354,19 @@
inline void* data() { return mData; }
};
-private:
- size_t mOpenAshmemSize;
-
-public:
- // TODO: Remove once ABI can be changed.
- size_t getBlobAshmemSize() const;
+ /**
+ * Returns the total amount of ashmem memory owned by this object.
+ *
+ * Note: for historical reasons, this does not include ashmem memory which
+ * is referenced by this Parcel, but which this parcel doesn't own (e.g.
+ * writeFileDescriptor is called without 'takeOwnership' true).
+ */
size_t getOpenAshmemSize() const;
+
+private:
+ // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference
+ // this
+ size_t getBlobAshmemSize() const;
};
// ---------------------------------------------------------------------------
@@ -1315,7 +1454,7 @@
template<typename T>
status_t Parcel::resizeOutVector(std::vector<T>* val) const {
int32_t size;
- status_t err = readInt32(&size);
+ status_t err = readOutVectorSizeWithCheck(sizeof(T), &size);
if (err != NO_ERROR) {
return err;
}
@@ -1330,7 +1469,7 @@
template<typename T>
status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
int32_t size;
- status_t err = readInt32(&size);
+ status_t err = readOutVectorSizeWithCheck(sizeof(T), &size);
if (err != NO_ERROR) {
return err;
}
@@ -1346,7 +1485,7 @@
template<typename T>
status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
int32_t size;
- status_t err = readInt32(&size);
+ status_t err = readOutVectorSizeWithCheck(sizeof(T), &size);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 9e4475c..88790a8 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -42,6 +42,7 @@
}
mStability = other.mStability;
}
+ ParcelableHolder(ParcelableHolder&& other) = default;
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
@@ -85,7 +86,7 @@
*ret = nullptr;
return android::BAD_VALUE;
}
- *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::static_pointer_cast<T>(mParcelable);
return android::OK;
}
this->mParcelPtr->setDataPosition(0);
@@ -104,7 +105,7 @@
return status;
}
this->mParcelPtr = nullptr;
- *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::static_pointer_cast<T>(mParcelable);
return android::OK;
}
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
index e658574..6f9eb5e 100644
--- a/libs/binder/include/binder/PermissionController.h
+++ b/libs/binder/include/binder/PermissionController.h
@@ -19,8 +19,7 @@
#ifndef __ANDROID_VNDK__
#include <binder/IPermissionController.h>
-
-#include <utils/threads.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index b9db5d7..675585e 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -18,10 +18,9 @@
#include <binder/IBinder.h>
#include <utils/KeyedVector.h>
-#include <utils/String8.h>
+#include <utils/Mutex.h>
#include <utils/String16.h>
-
-#include <utils/threads.h>
+#include <utils/String8.h>
#include <pthread.h>
@@ -30,11 +29,10 @@
class IPCThreadState;
-class ProcessState : public virtual RefBase
-{
+class ProcessState : public virtual RefBase {
public:
- static sp<ProcessState> self();
- static sp<ProcessState> selfOrNull();
+ static sp<ProcessState> self();
+ static sp<ProcessState> selfOrNull();
/* initWithDriver() can be used to configure libbinder to use
* a different binder driver dev node. It must be called *before*
@@ -44,94 +42,112 @@
*
* If this is called with nullptr, the behavior is the same as selfOrNull.
*/
- static sp<ProcessState> initWithDriver(const char *driver);
+ static sp<ProcessState> initWithDriver(const char* driver);
- sp<IBinder> getContextObject(const sp<IBinder>& caller);
+ sp<IBinder> getContextObject(const sp<IBinder>& caller);
- void startThreadPool();
+ void startThreadPool();
- bool becomeContextManager();
+ bool becomeContextManager();
- sp<IBinder> getStrongProxyForHandle(int32_t handle);
- void expungeHandle(int32_t handle, IBinder* binder);
+ sp<IBinder> getStrongProxyForHandle(int32_t handle);
+ void expungeHandle(int32_t handle, IBinder* binder);
- void spawnPooledThread(bool isMain);
-
- status_t setThreadPoolMaxThreadCount(size_t maxThreads);
- status_t enableOnewaySpamDetection(bool enable);
- void giveThreadPoolName();
+ void spawnPooledThread(bool isMain);
- String8 getDriverName();
+ status_t setThreadPoolMaxThreadCount(size_t maxThreads);
+ status_t enableOnewaySpamDetection(bool enable);
+ void giveThreadPoolName();
- ssize_t getKernelReferences(size_t count, uintptr_t* buf);
+ String8 getDriverName();
- // Only usable by the context manager.
- // This refcount includes:
- // 1. Strong references to the node by this and other processes
- // 2. Temporary strong references held by the kernel during a
- // transaction on the node.
- // It does NOT include local strong references to the node
- ssize_t getStrongRefCountForNode(const sp<BpBinder>& binder);
+ ssize_t getKernelReferences(size_t count, uintptr_t* buf);
- enum class CallRestriction {
- // all calls okay
- NONE,
- // log when calls are blocking
- ERROR_IF_NOT_ONEWAY,
- // abort process on blocking calls
- FATAL_IF_NOT_ONEWAY,
- };
- // Sets calling restrictions for all transactions in this process. This must be called
- // before any threads are spawned.
- void setCallRestriction(CallRestriction restriction);
+ // Only usable by the context manager.
+ // This refcount includes:
+ // 1. Strong references to the node by this and other processes
+ // 2. Temporary strong references held by the kernel during a
+ // transaction on the node.
+ // It does NOT include local strong references to the node
+ ssize_t getStrongRefCountForNode(const sp<BpBinder>& binder);
+
+ enum class CallRestriction {
+ // all calls okay
+ NONE,
+ // log when calls are blocking
+ ERROR_IF_NOT_ONEWAY,
+ // abort process on blocking calls
+ FATAL_IF_NOT_ONEWAY,
+ };
+ // Sets calling restrictions for all transactions in this process. This must be called
+ // before any threads are spawned.
+ void setCallRestriction(CallRestriction restriction);
+
+ /**
+ * Get the max number of threads that the kernel can start.
+ *
+ * Note: this is the lower bound. Additional threads may be started.
+ */
+ size_t getThreadPoolMaxThreadCount() const;
+
+ enum class DriverFeature {
+ ONEWAY_SPAM_DETECTION,
+ };
+ // Determine whether a feature is supported by the binder driver.
+ static bool isDriverFeatureEnabled(const DriverFeature feature);
private:
- static sp<ProcessState> init(const char *defaultDriver, bool requireDefault);
+ static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
+
+ static void onFork();
+ static void parentPostFork();
+ static void childPostFork();
friend class IPCThreadState;
friend class sp<ProcessState>;
- explicit ProcessState(const char* driver);
- ~ProcessState();
+ explicit ProcessState(const char* driver);
+ ~ProcessState();
- ProcessState(const ProcessState& o);
- ProcessState& operator=(const ProcessState& o);
- String8 makeBinderThreadName();
+ ProcessState(const ProcessState& o);
+ ProcessState& operator=(const ProcessState& o);
+ String8 makeBinderThreadName();
- struct handle_entry {
- IBinder* binder;
- RefBase::weakref_type* refs;
- };
+ struct handle_entry {
+ IBinder* binder;
+ RefBase::weakref_type* refs;
+ };
- handle_entry* lookupHandleLocked(int32_t handle);
+ handle_entry* lookupHandleLocked(int32_t handle);
- String8 mDriverName;
- int mDriverFD;
- void* mVMStart;
+ String8 mDriverName;
+ int mDriverFD;
+ void* mVMStart;
- // Protects thread count and wait variables below.
- pthread_mutex_t mThreadCountLock;
- // Broadcast whenever mWaitingForThreads > 0
- pthread_cond_t mThreadCountDecrement;
- // Number of binder threads current executing a command.
- size_t mExecutingThreadsCount;
- // Number of threads calling IPCThreadState::blockUntilThreadAvailable()
- size_t mWaitingForThreads;
- // Maximum number for binder threads allowed for this process.
- size_t mMaxThreads;
- // Time when thread pool was emptied
- int64_t mStarvationStartTimeMs;
+ // Protects thread count and wait variables below.
+ pthread_mutex_t mThreadCountLock;
+ // Broadcast whenever mWaitingForThreads > 0
+ pthread_cond_t mThreadCountDecrement;
+ // Number of binder threads current executing a command.
+ size_t mExecutingThreadsCount;
+ // Number of threads calling IPCThreadState::blockUntilThreadAvailable()
+ size_t mWaitingForThreads;
+ // Maximum number for binder threads allowed for this process.
+ size_t mMaxThreads;
+ // Time when thread pool was emptied
+ int64_t mStarvationStartTimeMs;
- mutable Mutex mLock; // protects everything below.
+ mutable Mutex mLock; // protects everything below.
- Vector<handle_entry>mHandleToObject;
+ Vector<handle_entry> mHandleToObject;
- bool mThreadPoolStarted;
- volatile int32_t mThreadPoolSeq;
+ bool mForked;
+ bool mThreadPoolStarted;
+ volatile int32_t mThreadPoolSeq;
- CallRestriction mCallRestriction;
+ CallRestriction mCallRestriction;
};
-
+
} // namespace android
// ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/RpcAddress.h b/libs/binder/include/binder/RpcAddress.h
deleted file mode 100644
index 5a3f3a6..0000000
--- a/libs/binder/include/binder/RpcAddress.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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/RpcCertificateFormat.h b/libs/binder/include/binder/RpcCertificateFormat.h
new file mode 100644
index 0000000..bc9d814
--- /dev/null
+++ b/libs/binder/include/binder/RpcCertificateFormat.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// Formats for serializing TLS certificate.
+
+#pragma once
+
+#include <string>
+
+namespace android {
+
+enum class RpcCertificateFormat {
+ PEM,
+ DER,
+};
+
+static inline std::string PrintToString(RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return "PEM";
+ case RpcCertificateFormat::DER:
+ return "DER";
+ default:
+ return "<unknown>";
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcKeyFormat.h b/libs/binder/include/binder/RpcKeyFormat.h
new file mode 100644
index 0000000..5099c2e
--- /dev/null
+++ b/libs/binder/include/binder/RpcKeyFormat.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// Formats for serializing TLS private keys.
+
+#pragma once
+
+#include <string>
+
+namespace android {
+
+enum class RpcKeyFormat {
+ PEM,
+ DER,
+};
+
+static inline std::string PrintToString(RpcKeyFormat format) {
+ switch (format) {
+ case RpcKeyFormat::PEM:
+ return "PEM";
+ case RpcKeyFormat::DER:
+ return "DER";
+ default:
+ return "<unknown>";
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 8f0c6fd..aaa812b 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -18,18 +18,16 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <mutex>
#include <thread>
-// 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 FdTrigger;
class RpcSocketAddress;
/**
@@ -44,9 +42,10 @@
* }
* server->join();
*/
-class RpcServer final : public virtual RefBase {
+class RpcServer final : public virtual RefBase, private RpcSession::EventListener {
public:
- static sp<RpcServer> make();
+ static sp<RpcServer> make(
+ std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
/**
* This represents a session for responses, e.g.:
@@ -56,12 +55,12 @@
* process B makes binder b and sends it to A
* A uses this 'back session' to send things back to B
*/
- [[nodiscard]] bool setupUnixDomainServer(const char* path);
+ [[nodiscard]] status_t setupUnixDomainServer(const char* path);
/**
* Creates an RPC server at the current port.
*/
- [[nodiscard]] bool setupVsockServer(unsigned int port);
+ [[nodiscard]] status_t setupVsockServer(unsigned int port);
/**
* Creates an RPC server at the current port using IPv4.
@@ -71,8 +70,14 @@
* Set |port| to 0 to pick an ephemeral port; see discussion of
* /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
* will be set to the picked port number, if it is not null.
+ *
+ * Set the IPv4 address for the socket to be listening on.
+ * "127.0.0.1" allows for local connections from the same device.
+ * "0.0.0.0" allows for connections on any IP address that the device may
+ * have
*/
- [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+ [[nodiscard]] status_t setupInetServer(const char* address, unsigned int port,
+ unsigned int* assignedPort);
/**
* If setup*Server has been successful, return true. Otherwise return false.
@@ -88,22 +93,27 @@
* Set up server using an external FD previously set up by releaseServer().
* Return false if there's already a server.
*/
- bool setupExternalServer(base::unique_fd serverFd);
-
- void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ [[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd);
/**
* This must be called before adding a client session.
*
* If this is not specified, this will be a single-threaded server.
*
- * TODO(b/185167543): these are currently created per client, but these
+ * TODO(b/167966510): these are currently created per client, but these
* should be shared.
*/
void setMaxThreads(size_t threads);
size_t getMaxThreads();
/**
+ * By default, the latest protocol version which is supported by a client is
+ * used. However, this can be used in order to prevent newer protocol
+ * versions from ever being used. This is expected to be useful for testing.
+ */
+ void setProtocolVersion(uint32_t version);
+
+ /**
* The root object can be retrieved by any client, without any
* authentication. TODO(b/183988761)
*
@@ -114,20 +124,43 @@
* Holds a weak reference to the root object.
*/
void setRootObjectWeak(const wp<IBinder>& binder);
+ /**
+ * Allows a root object to be created for each session
+ */
+ void setPerSessionRootObject(std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& object);
sp<IBinder> getRootObject();
/**
+ * See RpcTransportCtx::getCertificate
+ */
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat);
+
+ /**
+ * Runs join() in a background thread. Immediately returns.
+ */
+ void start();
+
+ /**
* You must have at least one client session before calling this.
*
- * TODO(b/185167543): way to shut down?
+ * If a client needs to actively terminate join, call shutdown() in a separate thread.
+ *
+ * At any given point, there can only be one thread calling join().
+ *
+ * Warning: if shutdown is called, this will return while the shutdown is
+ * still occurring. To ensure that the service is fully shutdown, you might
+ * want to call shutdown after 'join' returns.
*/
void join();
/**
- * Accept one connection on this server. You must have at least one client
- * session before calling this.
+ * Shut down any existing join(). Return true if successfully shut down, false otherwise
+ * (e.g. no join() is running). Will wait for the server to be fully
+ * shutdown.
+ *
+ * Warning: this will hang if it is called from its own thread.
*/
- [[nodiscard]] bool acceptOne();
+ [[nodiscard]] bool shutdown();
/**
* For debugging!
@@ -137,28 +170,32 @@
~RpcServer();
- // internal use only
-
- void onSessionTerminating(const sp<RpcSession>& session);
-
private:
friend sp<RpcServer>;
- RpcServer();
+ explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
- void establishConnection(sp<RpcServer>&& session, base::unique_fd clientFd);
- bool setupSocketServer(const RpcSocketAddress& address);
+ void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
+ void onSessionIncomingThreadEnded() override;
- bool mAgreedExperimental = false;
- bool mStarted = false; // TODO(b/185167543): support dynamically added clients
+ static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
+ const sockaddr_storage addr, socklen_t addrLen);
+ [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
+
+ const std::unique_ptr<RpcTransportCtx> mCtx;
size_t mMaxThreads = 1;
+ std::optional<uint32_t> mProtocolVersion;
base::unique_fd mServer; // socket we are accepting sessions on
std::mutex mLock; // for below
+ std::unique_ptr<std::thread> mJoinThread;
+ bool mJoinThreadRunning = false;
std::map<std::thread::id, std::thread> mConnectingThreads;
sp<IBinder> mRootObject;
wp<IBinder> mRootObjectWeak;
- std::map<int32_t, sp<RpcSession>> mSessions;
- int32_t mSessionIdCounter = 0;
+ std::function<sp<IBinder>(const sockaddr*, socklen_t)> mRootObjectFactory;
+ std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
+ std::unique_ptr<FdTrigger> mShutdownTrigger;
+ std::condition_variable mShutdownCv;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index bcc213c..1bc8464 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -17,7 +17,7 @@
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
+#include <binder/RpcTransport.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -26,16 +26,18 @@
#include <thread>
#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 RpcSocketAddress;
class RpcState;
+class RpcTransport;
+class FdTrigger;
+
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
/**
* This represents a session (group of connections) between a client
@@ -44,23 +46,76 @@
*/
class RpcSession final : public virtual RefBase {
public:
+ static constexpr size_t kDefaultMaxOutgoingThreads = 10;
+
+ // Create an RpcSession with default configuration (raw sockets).
static sp<RpcSession> make();
+ // Create an RpcSession with the given configuration. |serverRpcCertificateFormat| and
+ // |serverCertificate| must have values or be nullopt simultaneously. If they have values, set
+ // server certificate.
+ static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+
+ /**
+ * Set the maximum number of incoming threads allowed to be made (for things like callbacks).
+ * By default, this is 0. This must be called before setting up this connection as a client.
+ * Server sessions will inherits this value from RpcServer.
+ *
+ * If this is called, 'shutdown' on this session must also be called.
+ * Otherwise, a threadpool will leak.
+ *
+ * TODO(b/189955605): start these dynamically
+ */
+ void setMaxIncomingThreads(size_t threads);
+ size_t getMaxIncomingThreads();
+
+ /**
+ * Set the maximum number of outgoing threads allowed to be made.
+ * By default, this is |kDefaultMaxOutgoingThreads|. This must be called before setting up this
+ * connection as a client.
+ *
+ * This limits the number of outgoing threads on top of the remote peer setting. This RpcSession
+ * will only instantiate |min(maxOutgoingThreads, remoteMaxThreads)| outgoing threads, where
+ * |remoteMaxThreads| can be retrieved from the remote peer via |getRemoteMaxThreads()|.
+ */
+ void setMaxOutgoingThreads(size_t threads);
+ size_t getMaxOutgoingThreads();
+
+ /**
+ * By default, the minimum of the supported versions of the client and the
+ * server will be used. Usually, this API should only be used for debugging.
+ */
+ [[nodiscard]] bool setProtocolVersion(uint32_t version);
+ std::optional<uint32_t> getProtocolVersion();
+
/**
* This should be called once per thread, matching 'join' in the remote
* process.
*/
- [[nodiscard]] bool setupUnixDomainClient(const char* path);
+ [[nodiscard]] status_t setupUnixDomainClient(const char* path);
/**
* Connects to an RPC server at the CVD & port.
*/
- [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
+ [[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port);
/**
* Connects to an RPC server at the given address and port.
*/
- [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
+ [[nodiscard]] status_t setupInetClient(const char* addr, unsigned int port);
+
+ /**
+ * Starts talking to an RPC server which has already been connected to. This
+ * is expected to be used when another process has permission to connect to
+ * a binder RPC service, but this process only has permission to talk to
+ * that service.
+ *
+ * For convenience, if 'fd' is -1, 'request' will be called.
+ *
+ * For future compatibility, 'request' should not reference any stack data.
+ */
+ [[nodiscard]] status_t setupPreconnectedClient(base::unique_fd fd,
+ std::function<base::unique_fd()>&& request);
/**
* For debugging!
@@ -69,7 +124,7 @@
* response will never be satisfied. All data sent here will be
* unceremoniously cast down the bottomless pit, /dev/null.
*/
- [[nodiscard]] bool addNullDebuggingClient();
+ [[nodiscard]] status_t addNullDebuggingClient();
/**
* Query the other side of the session for the root object hosted by that
@@ -81,59 +136,129 @@
* Query the other side of the session for the maximum number of threads
* it supports (maximum number of concurrent non-nested synchronous transactions)
*/
- status_t getRemoteMaxThreads(size_t* maxThreads);
+ [[nodiscard]] status_t getRemoteMaxThreads(size_t* maxThreads);
- [[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
+ /**
+ * See RpcTransportCtx::getCertificate
+ */
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat);
+
+ /**
+ * Shuts down the service.
+ *
+ * For client sessions, wait can be true or false. For server sessions,
+ * waiting is not currently supported (will abort).
+ *
+ * Warning: this is currently not active/nice (the server isn't told we're
+ * shutting down). Being nicer to the server could potentially make it
+ * reclaim resources faster.
+ *
+ * If this is called w/ 'wait' true, then this will wait for shutdown to
+ * complete before returning. This will hang if it is called from the
+ * session threadpool (when processing received calls).
+ */
+ [[nodiscard]] bool shutdownAndWait(bool wait);
+
+ [[nodiscard]] status_t transact(const sp<IBinder>& binder, uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
- [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
+
+ /**
+ * Generally, you should not call this, unless you are testing error
+ * conditions, as this is called automatically by BpBinders when they are
+ * deleted (this is also why a raw pointer is used here)
+ */
+ [[nodiscard]] status_t sendDecStrong(const BpBinder* binder);
~RpcSession();
- wp<RpcServer> server();
+ /**
+ * Server if this session is created as part of a server (symmetrical to
+ * client servers). Otherwise, nullptr.
+ */
+ sp<RpcServer> server();
// internal only
- const std::unique_ptr<RpcState>& state() { return mState; }
-
- class PrivateAccessorForId {
- private:
- friend class RpcSession;
- friend class RpcState;
- explicit PrivateAccessorForId(const RpcSession* session) : mSession(session) {}
-
- const std::optional<int32_t> get() { return mSession->mId; }
-
- const RpcSession* mSession;
- };
- PrivateAccessorForId getPrivateAccessorForId() const { return PrivateAccessorForId(this); }
+ const std::unique_ptr<RpcState>& state() { return mRpcBinderState; }
private:
- friend PrivateAccessorForId;
friend sp<RpcSession>;
friend RpcServer;
- RpcSession();
+ friend RpcState;
+ explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
- status_t readId();
+ // for 'target', see RpcState::sendDecStrongToTarget
+ [[nodiscard]] status_t sendDecStrongToTarget(uint64_t address, size_t target);
- // transfer ownership of thread
- void preJoin(std::thread thread);
- // join on thread passed to preJoin
- void join(base::unique_fd client);
- void terminateLocked();
+ class EventListener : public virtual RefBase {
+ public:
+ virtual void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
+ virtual void onSessionIncomingThreadEnded() = 0;
+ };
+
+ class WaitForShutdownListener : public EventListener {
+ public:
+ void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
+ void onSessionIncomingThreadEnded() override;
+ void waitForShutdown(std::unique_lock<std::mutex>& lock, const sp<RpcSession>& session);
+
+ private:
+ std::condition_variable mCv;
+ };
+ friend WaitForShutdownListener;
struct RpcConnection : public RefBase {
- base::unique_fd fd;
+ std::unique_ptr<RpcTransport> rpcTransport;
// whether this or another thread is currently using this fd to make
// or receive transactions.
std::optional<pid_t> exclusiveTid;
+
+ bool allowNested = false;
};
- bool setupSocketClient(const RpcSocketAddress& address);
- bool setupOneSocketClient(const RpcSocketAddress& address, int32_t sessionId);
- void addClientConnection(base::unique_fd fd);
- void setForServer(const wp<RpcServer>& server, int32_t sessionId);
- sp<RpcConnection> assignServerToThisThread(base::unique_fd fd);
- bool removeServerConnection(const sp<RpcConnection>& connection);
+ [[nodiscard]] status_t readId();
+
+ // A thread joining a server must always call these functions in order, and
+ // cleanup is only programmed once into join. These are in separate
+ // functions in order to allow for different locks to be taken during
+ // different parts of setup.
+ //
+ // transfer ownership of thread (usually done while a lock is taken on the
+ // structure which originally owns the thread)
+ void preJoinThreadOwnership(std::thread thread);
+ // pass FD to thread and read initial connection information
+ struct PreJoinSetupResult {
+ // Server connection object associated with this
+ sp<RpcConnection> connection;
+ // Status of setup
+ status_t status;
+ };
+ PreJoinSetupResult preJoinSetup(std::unique_ptr<RpcTransport> rpcTransport);
+ // join on thread passed to preJoinThreadOwnership
+ static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
+
+ [[nodiscard]] status_t setupClient(
+ const std::function<status_t(const std::vector<uint8_t>& sessionId, bool incoming)>&
+ connectAndInit);
+ [[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
+ [[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
+ const std::vector<uint8_t>& sessionId,
+ bool incoming);
+ [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd,
+ const std::vector<uint8_t>& sessionId,
+ bool incoming);
+ [[nodiscard]] status_t addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
+ [[nodiscard]] status_t addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport,
+ bool init);
+ [[nodiscard]] bool setForServer(const wp<RpcServer>& server,
+ const wp<RpcSession::EventListener>& eventListener,
+ const std::vector<uint8_t>& sessionId,
+ const sp<IBinder>& sessionSpecificRoot);
+ sp<RpcConnection> assignIncomingConnectionToThisThread(
+ std::unique_ptr<RpcTransport> rpcTransport);
+ [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
+
+ [[nodiscard]] status_t initShutdownTrigger();
enum class ConnectionUse {
CLIENT,
@@ -141,12 +266,14 @@
CLIENT_REFCOUNT,
};
- // RAII object for session connection
+ // Object representing exclusive access to a connection.
class ExclusiveConnection {
public:
- explicit ExclusiveConnection(const sp<RpcSession>& session, ConnectionUse use);
+ [[nodiscard]] static status_t find(const sp<RpcSession>& session, ConnectionUse use,
+ ExclusiveConnection* connection);
+
~ExclusiveConnection();
- const base::unique_fd& fd() { return mConnection->fd; }
+ const sp<RpcConnection>& get() { return mConnection; }
private:
static void findConnection(pid_t tid, sp<RpcConnection>* exclusive,
@@ -163,13 +290,15 @@
bool mReentrant = false;
};
- // On the other side of a session, for each of mClientConnections here, there should
- // be one of mServerConnections on the other side (and vice versa).
+ const std::unique_ptr<RpcTransportCtx> mCtx;
+
+ // On the other side of a session, for each of mOutgoing here, there should
+ // be one of mIncoming on the other side (and vice versa).
//
// For the simplest session, a single server with one client, you would
// have:
- // - the server has a single 'mServerConnections' and a thread listening on this
- // - the client has a single 'mClientConnections' and makes calls to this
+ // - the server has a single 'mIncoming' and a thread listening on this
+ // - the client has a single 'mOutgoing' 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.
@@ -178,27 +307,36 @@
// serve calls to the server at all times (e.g. if it hosts a callback)
wp<RpcServer> mForServer; // maybe null, for client sessions
+ sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
+ wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
- // TODO(b/183988761): this shouldn't be guessable
- std::optional<int32_t> mId;
+ // session-specific root object (if a different root is used for each
+ // session)
+ sp<IBinder> mSessionSpecificRootObject;
- std::unique_ptr<RpcState> mState;
+ std::vector<uint8_t> mId;
+
+ std::unique_ptr<FdTrigger> mShutdownTrigger;
+
+ std::unique_ptr<RpcState> mRpcBinderState;
std::mutex mMutex; // for all below
- std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
- size_t mWaitingThreads = 0;
- // hint index into clients, ++ when sending an async transaction
- size_t mClientConnectionsOffset = 0;
- std::vector<sp<RpcConnection>> mClientConnections;
- std::vector<sp<RpcConnection>> mServerConnections;
+ size_t mMaxIncomingThreads = 0;
+ size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
+ std::optional<uint32_t> mProtocolVersion;
- // TODO(b/185167543): use for reverse sessions (allow client to also
- // serve calls on a session).
- // TODO(b/185167543): allow sharing between different sessions in a
- // process? (or combine with mServerConnections)
- std::map<std::thread::id, std::thread> mThreads;
- bool mTerminated = false;
+ std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
+
+ struct ThreadState {
+ size_t mWaitingThreads = 0;
+ // hint index into clients, ++ when sending an async transaction
+ size_t mOutgoingOffset = 0;
+ std::vector<sp<RpcConnection>> mOutgoing;
+ size_t mMaxIncoming = 0;
+ std::vector<sp<RpcConnection>> mIncoming;
+ std::map<std::thread::id, std::thread> mThreads;
+ } mConnections;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
new file mode 100644
index 0000000..751c4f9
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation may use plain sockets or TLS.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+#include <binder/RpcCertificateFormat.h>
+
+#include <sys/uio.h>
+
+namespace android {
+
+class FdTrigger;
+
+// Represents a socket connection.
+// No thread-safety is guaranteed for these APIs.
+class RpcTransport {
+public:
+ virtual ~RpcTransport() = default;
+
+ // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
+ [[nodiscard]] virtual status_t peek(void *buf, size_t size, size_t *out_size) = 0;
+
+ /**
+ * Read (or write), but allow to be interrupted by a trigger.
+ *
+ * iovs - array of iovecs to perform the operation on. The elements
+ * of the array may be modified by this method.
+ *
+ * altPoll - function to be called instead of polling, when needing to wait
+ * to read/write data. If this returns an error, that error is returned from
+ * this function.
+ *
+ * Return:
+ * OK - succeeded in completely processing 'size'
+ * error - interrupted (failure or trigger)
+ */
+ [[nodiscard]] virtual status_t interruptableWriteFully(
+ FdTrigger *fdTrigger, iovec *iovs, int niovs,
+ const std::function<status_t()> &altPoll) = 0;
+ [[nodiscard]] virtual status_t interruptableReadFully(
+ FdTrigger *fdTrigger, iovec *iovs, int niovs,
+ const std::function<status_t()> &altPoll) = 0;
+
+protected:
+ RpcTransport() = default;
+};
+
+// Represents the context that generates the socket connection.
+// All APIs are thread-safe. See RpcTransportCtxRaw and RpcTransportCtxTls for details.
+class RpcTransportCtx {
+public:
+ virtual ~RpcTransportCtx() = default;
+
+ // Create a new RpcTransport object.
+ //
+ // Implementation details: for TLS, this function may incur I/O. |fdTrigger| may be used
+ // to interrupt I/O. This function blocks until handshake is finished.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
+ android::base::unique_fd fd, FdTrigger *fdTrigger) const = 0;
+
+ // Return the preconfigured certificate of this context.
+ //
+ // Implementation details:
+ // - For raw sockets, this always returns empty string.
+ // - For TLS, this returns the certificate. See RpcTransportTls for details.
+ [[nodiscard]] virtual std::vector<uint8_t> getCertificate(
+ RpcCertificateFormat format) const = 0;
+
+protected:
+ RpcTransportCtx() = default;
+};
+
+// A factory class that generates RpcTransportCtx.
+// All APIs are thread-safe.
+class RpcTransportCtxFactory {
+public:
+ virtual ~RpcTransportCtxFactory() = default;
+ // Creates server context.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newServerCtx() const = 0;
+
+ // Creates client context.
+ [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newClientCtx() const = 0;
+
+ // Return a short description of this transport (e.g. "raw"). For logging / debugging / testing
+ // only.
+ [[nodiscard]] virtual const char *toCString() const = 0;
+
+protected:
+ RpcTransportCtxFactory() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcTransportRaw.h b/libs/binder/include/binder/RpcTransportRaw.h
new file mode 100644
index 0000000..6fb1f92
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransportRaw.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses plain sockets.
+// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx.
+
+#pragma once
+
+#include <memory>
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS disabled.
+class RpcTransportCtxFactoryRaw : public RpcTransportCtxFactory {
+public:
+ static std::unique_ptr<RpcTransportCtxFactory> make();
+
+ std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
+ std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
+ const char* toCString() const override;
+
+private:
+ RpcTransportCtxFactoryRaw() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index f4bfac8..ce4362f 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -44,10 +44,9 @@
// to old servers, and new servers know how to interpret the 8-byte result,
// they can still communicate.
//
-// Every binder object has a stability level associated with it, and when
-// communicating with a binder, we make sure that the command we sent is one
-// that it knows how to process. The summary of stability of a binder is
-// represented by a Stability::Category object.
+// This class is specifically about (1). (2) is not currently tracked by
+// libbinder for regular binder calls, and everything on the system uses the
+// same copy of libbinder.
class Stability final {
public:
@@ -100,7 +99,7 @@
static void markVintf(IBinder* binder);
// WARNING: for debugging only
- static void debugLogStability(const std::string& tag, const sp<IBinder>& binder);
+ static std::string debugToString(const sp<IBinder>& binder);
// WARNING: This is only ever expected to be called by auto-generated code or tests.
// You likely want to change or modify the stability of the interface you are using.
@@ -128,7 +127,10 @@
static void tryMarkCompilationUnit(IBinder* binder);
- enum Level : uint8_t {
+ // Currently, we use int16_t for Level so that it can fit in BBinder.
+ // However, on the wire, we have 4 bytes reserved for stability, so whenever
+ // we ingest a Level, we always accept an int32_t.
+ enum Level : int16_t {
UNDECLARED = 0,
VENDOR = 0b000011,
@@ -136,38 +138,6 @@
VINTF = 0b111111,
};
- // This is the format of stability passed on the wire.
- struct Category {
- static inline Category fromRepr(int32_t representation) {
- return *reinterpret_cast<Category*>(&representation);
- }
- int32_t repr() const {
- return *reinterpret_cast<const int32_t*>(this);
- }
- static inline Category currentFromLevel(Level level);
-
- bool operator== (const Category& o) const {
- return repr() == o.repr();
- }
- bool operator!= (const Category& o) const {
- return !(*this == o);
- }
-
- std::string debugString();
-
- // This is the version of the wire protocol associated with the host
- // process of a particular binder. As the wire protocol changes, if
- // sending a transaction to a binder with an old version, the Parcel
- // class must write parcels according to the version documented here.
- uint8_t version;
-
- uint8_t reserved[2];
-
- // bitmask of Stability::Level
- Level level;
- };
- static_assert(sizeof(Category) == sizeof(int32_t));
-
// returns the stability according to how this was built
static Level getLocalLevel();
@@ -180,18 +150,18 @@
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, uint32_t flags);
+ __attribute__((warn_unused_result)) static status_t setRepr(IBinder* binder, int32_t setting,
+ uint32_t flags);
// get stability information as encoded on the wire
- static Category getCategory(IBinder* binder);
+ static int16_t getRepr(IBinder* binder);
// whether a transaction on binder is allowed, if the transaction
// is done from a context with a specific stability level
- static bool check(Category provided, Level required);
+ static bool check(int16_t provided, Level required);
- static bool isDeclaredLevel(Level level);
- static std::string levelString(Level level);
+ static bool isDeclaredLevel(int32_t level);
+ static std::string levelString(int32_t level);
Stability();
};
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index aaafa36..af34695 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -117,6 +117,10 @@
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
+ // Convenience API to replace a Parcel with a status value, w/o requiring
+ // calling multiple APIs (makes generated code smaller).
+ status_t writeOverParcel(Parcel* parcel) const;
+
// Set one of the pre-defined exception types defined above.
void setException(int32_t ex, const String8& message);
// Set a service specific exception with error code.
diff --git a/libs/binder/include_activitymanager/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h
index b772b80..abc7f1d 100644
--- a/libs/binder/include_activitymanager/binder/ActivityManager.h
+++ b/libs/binder/include_activitymanager/binder/ActivityManager.h
@@ -18,10 +18,9 @@
#ifndef __ANDROID_VNDK__
-#include <binder/IActivityManager.h>
#include <android/app/ProcessStateEnum.h>
-
-#include <utils/threads.h>
+#include <binder/IActivityManager.h>
+#include <utils/Mutex.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
new file mode 100644
index 0000000..5baa4d7
--- /dev/null
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <sys/socket.h>
+
+extern "C" {
+
+struct AIBinder;
+
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server and joins before returning.
+bool RunRpcServer(AIBinder* service, unsigned int port);
+
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
+ void* param);
+
+// Starts an RPC server on a given port and a given root IBinder factory.
+// RunRpcServerWithFactory acts like RunRpcServerCallback, but instead of
+// assigning single root IBinder object to all connections, factory is called
+// whenever a client connects, making it possible to assign unique IBinder
+// object to each client.
+bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
+ void* factoryContext, unsigned int port);
+
+AIBinder* RpcClient(unsigned int cid, unsigned int port);
+
+// Connect to an RPC server with preconnected file descriptors.
+//
+// requestFd should connect to the server and return a valid file descriptor, or
+// -1 if connection fails.
+//
+// param will be passed to requestFd. Callers can use param to pass contexts to
+// the requestFd function.
+AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param);
+
+}
diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h
new file mode 100644
index 0000000..ab64828
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcAuth.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+// An interface with a function that configures the SSL_CTX object with authentication information,
+// including certificates and private keys.
+class RpcAuth {
+public:
+ virtual ~RpcAuth() = default;
+
+ // The keys and certificates to provide is up to the implementation. Multiple calls to
+ // |configure()| may configure |ctx| with the same keys / certificates, or generate a
+ // different key / certificate every time |configure()| is called.
+ //
+ // It is guaranteed that, when a context object (RpcTransportCtx) is created,
+ // libbinder_tls calls |configure()| on server RpcAuth exactly once.
+ //
+ // The implementation may use the following function to set the private
+ // keys and certificates:
+ // - SSL_CTX_use_PrivateKey
+ // - SSL_CTX_use_certificate
+ // - SSL_CTX_set*_chain
+ // - SSL_CTX_add0_chain_cert
+ [[nodiscard]] virtual status_t configure(SSL_CTX* ctx) = 0;
+};
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcCertificateVerifier.h b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
new file mode 100644
index 0000000..800e375
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+// An interface with a function that verifies a peer certificate. It is a wrapper over the custom
+// verify function (see SSL_CTX_set_custom_verify).
+class RpcCertificateVerifier {
+public:
+ virtual ~RpcCertificateVerifier() = default;
+
+ // The implementation may use the following function to get
+ // the peer certificate and chain:
+ // - SSL_get_peer_certificate
+ // - SSL_get_peer_cert_chain
+ // - SSL_get_peer_full_cert_chain
+ //
+ // The implementation should return OK on success or error codes on error. For example:
+ // - PERMISSION_DENIED for rejected certificates
+ // - NO_INIT for not presenting a certificate when requested
+ // - UNKNOWN_ERROR for other errors
+ virtual status_t verify(const SSL* ssl, uint8_t* outAlert) = 0;
+};
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcTlsUtils.h b/libs/binder/include_tls/binder/RpcTlsUtils.h
new file mode 100644
index 0000000..591926b
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcTlsUtils.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+// Utilities for serializing and deserializing X509 certificates.
+
+#pragma once
+
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcKeyFormat.h>
+
+namespace android {
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& data,
+ RpcCertificateFormat format);
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
+
+// Deserialize an un-encrypted private key.
+bssl::UniquePtr<EVP_PKEY> deserializeUnencryptedPrivatekey(const std::vector<uint8_t>& data,
+ RpcKeyFormat format);
+
+// Serialize a private key in un-encrypted form.
+std::vector<uint8_t> serializeUnencryptedPrivatekey(EVP_PKEY* pkey, RpcKeyFormat format);
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
new file mode 100644
index 0000000..8a11125
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses TLS.
+
+#pragma once
+
+#include <binder/RpcAuth.h>
+#include <binder/RpcCertificateVerifier.h>
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS enabled with self-signed certificate.
+class RpcTransportCtxFactoryTls : public RpcTransportCtxFactory {
+public:
+ static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>,
+ std::unique_ptr<RpcAuth>);
+
+ std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
+ std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
+ const char* toCString() const override;
+
+private:
+ RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier,
+ std::unique_ptr<RpcAuth> auth)
+ : mCertVerifier(std::move(verifier)), mAuth(std::move(auth)){};
+
+ std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
+ std::unique_ptr<RpcAuth> mAuth;
+};
+
+} // namespace android
diff --git a/libs/binder/libbinder.arm32.map b/libs/binder/libbinder.arm32.map
deleted file mode 100644
index 9f10b67..0000000
--- a/libs/binder/libbinder.arm32.map
+++ /dev/null
@@ -1,1394 +0,0 @@
-LIBBINDER {
- global:
- getBinderKernelReferences;
- kDefaultDriver;
- _ZN7android10AllocationC1ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEEij;
- _ZN7android10AllocationC2ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEEij;
- _ZN7android10AllocationD0Ev;
- _ZN7android10AllocationD1Ev;
- _ZN7android10AllocationD2Ev;
- _ZN7android10IInterface8asBinderEPKS0_;
- _ZN7android10IInterface8asBinderERKNS_2spIS0_EE;
- _ZN7android10IInterfaceC2Ev;
- _ZN7android10IInterfaceD0Ev;
- _ZN7android10IInterfaceD1Ev;
- _ZN7android10IInterfaceD2Ev;
- _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij;
- _ZN7android10MemoryBaseC2ERKNS_2spINS_11IMemoryHeapEEEij;
- _ZN7android10MemoryBaseD0Ev;
- _ZN7android10MemoryBaseD1Ev;
- _ZN7android10MemoryBaseD2Ev;
- _ZN7android10RpcAddress14readFromParcelERKNS_6ParcelE;
- _ZN7android10RpcAddress15fromRawEmbeddedEPKNS_14RpcWireAddressE;
- _ZN7android10RpcAddress4zeroEv;
- _ZN7android10RpcAddress6uniqueEv;
- _ZN7android10RpcAddressC1Ev;
- _ZN7android10RpcAddressC2Ev;
- _ZN7android10RpcAddressD1Ev;
- _ZN7android10RpcAddressD2Ev;
- _ZN7android10RpcSession12setForServerERKNS_2wpINS_9RpcServerEEEi;
- _ZN7android10RpcSession13getRootObjectEv;
- _ZN7android10RpcSession13sendDecStrongERKNS_10RpcAddressE;
- _ZN7android10RpcSession15setupInetClientEPKcj;
- _ZN7android10RpcSession15terminateLockedEv;
- _ZN7android10RpcSession16setupVsockClientEjj;
- _ZN7android10RpcSession17setupSocketClientERKNS_16RpcSocketAddressE;
- _ZN7android10RpcSession19addClientConnectionENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession19ExclusiveConnection14findConnectionEiPNS_2spINS0_13RpcConnectionEEES5_RNSt3__16vectorIS4_NS6_9allocatorIS4_EEEEj;
- _ZN7android10RpcSession19ExclusiveConnectionC1ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionC2ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionD1Ev;
- _ZN7android10RpcSession19ExclusiveConnectionD2Ev;
- _ZN7android10RpcSession19getRemoteMaxThreadsEPj;
- _ZN7android10RpcSession20setupOneSocketClientERKNS_16RpcSocketAddressEi;
- _ZN7android10RpcSession21setupUnixDomainClientEPKc;
- _ZN7android10RpcSession22addNullDebuggingClientEv;
- _ZN7android10RpcSession22removeServerConnectionERKNS_2spINS0_13RpcConnectionEEE;
- _ZN7android10RpcSession24assignServerToThisThreadENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4joinENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4makeEv;
- _ZN7android10RpcSession6readIdEv;
- _ZN7android10RpcSession6serverEv;
- _ZN7android10RpcSession7preJoinENSt3__16threadE;
- _ZN7android10RpcSession8transactERKNS_10RpcAddressEjRKNS_6ParcelEPS4_j;
- _ZN7android10RpcSessionC1Ev;
- _ZN7android10RpcSessionC2Ev;
- _ZN7android10RpcSessionD0Ev;
- _ZN7android10RpcSessionD1Ev;
- _ZN7android10RpcSessionD2Ev;
- _ZN7android10TextOutputC2Ev;
- _ZN7android10TextOutputD0Ev;
- _ZN7android10TextOutputD1Ev;
- _ZN7android10TextOutputD2Ev;
- _ZN7android10zeroMemoryEPhj;
- _ZN7android11BnInterfaceINS_11IMemoryHeapEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_14IShellCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_15IResultReceiverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_21IPermissionControllerEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IClientCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IServiceManagerEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os16IServiceCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm21IPackageManagerNativeEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm22IPackageChangeObserverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7IMemoryEE10onAsBinderEv;
- _ZN7android11IMemoryHeap10descriptorE;
- _ZN7android11IMemoryHeap11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android11IMemoryHeap12default_implE;
- _ZN7android11IMemoryHeap14getDefaultImplEv;
- _ZN7android11IMemoryHeap14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android11IMemoryHeapC2Ev;
- _ZN7android11IMemoryHeapD0Ev;
- _ZN7android11IMemoryHeapD1Ev;
- _ZN7android11IMemoryHeapD2Ev;
- _ZN7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android12BnMemoryHeapC2Ev;
- _ZN7android12BnMemoryHeapD0Ev;
- _ZN7android12BnMemoryHeapD1Ev;
- _ZN7android12BnMemoryHeapD2Ev;
- _ZN7android12BpMemoryHeapC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapD0Ev;
- _ZN7android12BpMemoryHeapD1Ev;
- _ZN7android12BpMemoryHeapD2Ev;
- _ZN7android12gTextBuffersE;
- _ZN7android12MemoryDealer10deallocateEj;
- _ZN7android12MemoryDealer22getAllocationAlignmentEv;
- _ZN7android12MemoryDealer8allocateEj;
- _ZN7android12MemoryDealerC1EjPKcj;
- _ZN7android12MemoryDealerC2EjPKcj;
- _ZN7android12MemoryDealerD0Ev;
- _ZN7android12MemoryDealerD1Ev;
- _ZN7android12MemoryDealerD2Ev;
- _ZN7android12printHexDataEiPKvjjijbPFvPvPKcES2_;
- _ZN7android12ProcessState10selfOrNullEv;
- _ZN7android12ProcessState13expungeHandleEiPNS_7IBinderE;
- _ZN7android12ProcessState13getDriverNameEv;
- _ZN7android12ProcessState14initWithDriverEPKc;
- _ZN7android12ProcessState15startThreadPoolEv;
- _ZN7android12ProcessState16getContextObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android12ProcessState17spawnPooledThreadEb;
- _ZN7android12ProcessState18giveThreadPoolNameEv;
- _ZN7android12ProcessState18lookupHandleLockedEi;
- _ZN7android12ProcessState18setCallRestrictionENS0_15CallRestrictionE;
- _ZN7android12ProcessState19getKernelReferencesEjPj;
- _ZN7android12ProcessState20becomeContextManagerEv;
- _ZN7android12ProcessState20makeBinderThreadNameEv;
- _ZN7android12ProcessState23getStrongProxyForHandleEi;
- _ZN7android12ProcessState24getStrongRefCountForNodeERKNS_2spINS_8BpBinderEEE;
- _ZN7android12ProcessState25enableOnewaySpamDetectionEb;
- _ZN7android12ProcessState27setThreadPoolMaxThreadCountEj;
- _ZN7android12ProcessState4initEPKcb;
- _ZN7android12ProcessState4selfEv;
- _ZN7android12ProcessStateC1EPKc;
- _ZN7android12ProcessStateC2EPKc;
- _ZN7android12ProcessStateD0Ev;
- _ZN7android12ProcessStateD1Ev;
- _ZN7android12ProcessStateD2Ev;
- _ZN7android13printTypeCodeEjPFvPvPKcES0_;
- _ZN7android14IPCThreadState10freeBufferEPNS_6ParcelEPKhjPKyj;
- _ZN7android14IPCThreadState10selfOrNullEv;
- _ZN7android14IPCThreadState11clearCallerEv;
- _ZN7android14IPCThreadState11stopProcessEb;
- _ZN7android14IPCThreadState12setupPollingEPi;
- _ZN7android14IPCThreadState13decWeakHandleEi;
- _ZN7android14IPCThreadState13expungeHandleEiPNS_7IBinderE;
- _ZN7android14IPCThreadState13flushCommandsEv;
- _ZN7android14IPCThreadState13flushIfNeededEv;
- _ZN7android14IPCThreadState13incWeakHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState14clearLastErrorEv;
- _ZN7android14IPCThreadState14executeCommandEi;
- _ZN7android14IPCThreadState14joinThreadPoolEb;
- _ZN7android14IPCThreadState14talkWithDriverEb;
- _ZN7android14IPCThreadState15decStrongHandleEi;
- _ZN7android14IPCThreadState15incStrongHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi;
- _ZN7android14IPCThreadState16threadDestructorEPv;
- _ZN7android14IPCThreadState18setCallRestrictionENS_12ProcessState15CallRestrictionE;
- _ZN7android14IPCThreadState19setStrictModePolicyEi;
- _ZN7android14IPCThreadState19setTheContextObjectERKNS_2spINS_7BBinderEEE;
- _ZN7android14IPCThreadState20clearCallingIdentityEv;
- _ZN7android14IPCThreadState20getAndExecuteCommandEv;
- _ZN7android14IPCThreadState20getProcessFreezeInfoEiPbS1_;
- _ZN7android14IPCThreadState20getProcessFreezeInfoEiPjS1_;
- _ZN7android14IPCThreadState20handlePolledCommandsEv;
- _ZN7android14IPCThreadState20processPendingDerefsEv;
- _ZN7android14IPCThreadState20writeTransactionDataEijijRKNS_6ParcelEPi;
- _ZN7android14IPCThreadState22attemptIncStrongHandleEi;
- _ZN7android14IPCThreadState22clearCallingWorkSourceEv;
- _ZN7android14IPCThreadState22clearDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState22processPostWriteDerefsEv;
- _ZN7android14IPCThreadState22restoreCallingIdentityEx;
- _ZN7android14IPCThreadState23setCallingWorkSourceUidEj;
- _ZN7android14IPCThreadState24clearPropagateWorkSourceEv;
- _ZN7android14IPCThreadState24requestDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState24restoreCallingWorkSourceEx;
- _ZN7android14IPCThreadState25blockUntilThreadAvailableEv;
- _ZN7android14IPCThreadState27disableBackgroundSchedulingEb;
- _ZN7android14IPCThreadState28backgroundSchedulingDisabledEv;
- _ZN7android14IPCThreadState29setLastTransactionBinderFlagsEi;
- _ZN7android14IPCThreadState41setCallingWorkSourceUidWithoutPropagationEj;
- _ZN7android14IPCThreadState4selfEv;
- _ZN7android14IPCThreadState6freezeEibj;
- _ZN7android14IPCThreadState7processEv;
- _ZN7android14IPCThreadState8shutdownEv;
- _ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j;
- _ZN7android14IPCThreadState9sendReplyERKNS_6ParcelEj;
- _ZN7android14IPCThreadStateC1Ev;
- _ZN7android14IPCThreadStateC2Ev;
- _ZN7android14IPCThreadStateD1Ev;
- _ZN7android14IPCThreadStateD2Ev;
- _ZN7android14IShellCallback10descriptorE;
- _ZN7android14IShellCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android14IShellCallback12default_implE;
- _ZN7android14IShellCallback14getDefaultImplEv;
- _ZN7android14IShellCallback14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android14IShellCallbackC2Ev;
- _ZN7android14IShellCallbackD0Ev;
- _ZN7android14IShellCallbackD1Ev;
- _ZN7android14IShellCallbackD2Ev;
- _ZN7android14MemoryHeapBase4initEiPvjiPKc;
- _ZN7android14MemoryHeapBase5mapfdEibjl;
- _ZN7android14MemoryHeapBase7disposeEv;
- _ZN7android14MemoryHeapBaseC1Eijjl;
- _ZN7android14MemoryHeapBaseC1EjjPKc;
- _ZN7android14MemoryHeapBaseC1EPKcjj;
- _ZN7android14MemoryHeapBaseC1Ev;
- _ZN7android14MemoryHeapBaseC2Eijjl;
- _ZN7android14MemoryHeapBaseC2EjjPKc;
- _ZN7android14MemoryHeapBaseC2EPKcjj;
- _ZN7android14MemoryHeapBaseC2Ev;
- _ZN7android14MemoryHeapBaseD0Ev;
- _ZN7android14MemoryHeapBaseD1Ev;
- _ZN7android14MemoryHeapBaseD2Ev;
- _ZN7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android15checkPermissionERKNS_8String16Eij;
- _ZN7android15IResultReceiver10descriptorE;
- _ZN7android15IResultReceiver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android15IResultReceiver12default_implE;
- _ZN7android15IResultReceiver14getDefaultImplEv;
- _ZN7android15IResultReceiver14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android15IResultReceiverC2Ev;
- _ZN7android15IResultReceiverD0Ev;
- _ZN7android15IResultReceiverD1Ev;
- _ZN7android15IResultReceiverD2Ev;
- _ZN7android15IServiceManagerC2Ev;
- _ZN7android15IServiceManagerD0Ev;
- _ZN7android15IServiceManagerD1Ev;
- _ZN7android15IServiceManagerD2Ev;
- _ZN7android15PermissionCache10purgeCacheEv;
- _ZN7android15PermissionCache15checkPermissionERKNS_8String16Eij;
- _ZN7android15PermissionCache22checkCallingPermissionERKNS_8String16E;
- _ZN7android15PermissionCache22checkCallingPermissionERKNS_8String16EPiS4_;
- _ZN7android15PermissionCache5cacheERKNS_8String16Ejb;
- _ZN7android15PermissionCache5purgeEv;
- _ZN7android15PermissionCacheC1Ev;
- _ZN7android15PermissionCacheC2Ev;
- _ZN7android15stringForIndentEi;
- _ZN7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android18BufferedTextOutput10moveIndentEi;
- _ZN7android18BufferedTextOutput10pushBundleEv;
- _ZN7android18BufferedTextOutput5printEPKcj;
- _ZN7android18BufferedTextOutput9popBundleEv;
- _ZN7android18BufferedTextOutputC2Ej;
- _ZN7android18BufferedTextOutputD0Ev;
- _ZN7android18BufferedTextOutputD1Ev;
- _ZN7android18BufferedTextOutputD2Ev;
- _ZN7android18ServiceManagerShim10addServiceERKNS_8String16ERKNS_2spINS_7IBinderEEEbi;
- _ZN7android18ServiceManagerShim10isDeclaredERKNS_8String16E;
- _ZN7android18ServiceManagerShim12listServicesEi;
- _ZN7android18ServiceManagerShim14waitForServiceERKNS_8String16E;
- _ZN7android18ServiceManagerShim16updatableViaApexERKNS_8String16E;
- _ZN7android18ServiceManagerShim20getDeclaredInstancesERKNS_8String16E;
- _ZN7android18ServiceManagerShimC1ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18ServiceManagerShimC2ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18the_context_objectE;
- _ZN7android20PermissionController10getServiceEv;
- _ZN7android20PermissionController13getPackageUidERKNS_8String16Ei;
- _ZN7android20PermissionController15checkPermissionERKNS_8String16Eii;
- _ZN7android20PermissionController17getPackagesForUidEjRNS_6VectorINS_8String16EEE;
- _ZN7android20PermissionController19isRuntimePermissionERKNS_8String16E;
- _ZN7android20PermissionController6noteOpERKNS_8String16EiS3_;
- _ZN7android20PermissionControllerC1Ev;
- _ZN7android20PermissionControllerC2Ev;
- _ZN7android21defaultServiceManagerEv;
- _ZN7android21IPermissionController10descriptorE;
- _ZN7android21IPermissionController11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android21IPermissionController12default_implE;
- _ZN7android21IPermissionController14getDefaultImplEv;
- _ZN7android21IPermissionController14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android21IPermissionControllerC2Ev;
- _ZN7android21IPermissionControllerD0Ev;
- _ZN7android21IPermissionControllerD1Ev;
- _ZN7android21IPermissionControllerD2Ev;
- _ZN7android22BnPermissionController10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android22checkCallingPermissionERKNS_8String16E;
- _ZN7android22checkCallingPermissionERKNS_8String16EPiS3_;
- _ZN7android22SimpleBestFitAllocator10deallocateEj;
- _ZN7android22SimpleBestFitAllocator12kMemoryAlignE;
- _ZN7android22SimpleBestFitAllocator5allocEjj;
- _ZN7android22SimpleBestFitAllocator7deallocEj;
- _ZN7android22SimpleBestFitAllocator8allocateEjj;
- _ZN7android22SimpleBestFitAllocatorC1Ej;
- _ZN7android22SimpleBestFitAllocatorC2Ej;
- _ZN7android22SimpleBestFitAllocatorD1Ev;
- _ZN7android22SimpleBestFitAllocatorD2Ev;
- _ZN7android24setDefaultServiceManagerERKNS_2spINS_15IServiceManagerEEE;
- _ZN7android2os15IClientCallback10descriptorE;
- _ZN7android2os15IClientCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IClientCallback12default_implE;
- _ZN7android2os15IClientCallback14getDefaultImplEv;
- _ZN7android2os15IClientCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IClientCallbackC2Ev;
- _ZN7android2os15IClientCallbackD0Ev;
- _ZN7android2os15IClientCallbackD1Ev;
- _ZN7android2os15IClientCallbackD2Ev;
- _ZN7android2os15IServiceManager10descriptorE;
- _ZN7android2os15IServiceManager11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IServiceManager12default_implE;
- _ZN7android2os15IServiceManager14getDefaultImplEv;
- _ZN7android2os15IServiceManager14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IServiceManagerC2Ev;
- _ZN7android2os15IServiceManagerD0Ev;
- _ZN7android2os15IServiceManagerD1Ev;
- _ZN7android2os15IServiceManagerD2Ev;
- _ZN7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnClientCallbackC2Ev;
- _ZN7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnServiceManagerC2Ev;
- _ZN7android2os16BpClientCallback9onClientsERKNS_2spINS_7IBinderEEEb;
- _ZN7android2os16BpClientCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpClientCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10addServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEEbi;
- _ZN7android2os16BpServiceManager10getServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10isDeclaredERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPb;
- _ZN7android2os16BpServiceManager12checkServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager12listServicesEiPNSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEE;
- _ZN7android2os16BpServiceManager16updatableViaApexERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_8optionalIS8_EE;
- _ZN7android2os16BpServiceManager19getServiceDebugInfoEPNSt3__16vectorINS0_16ServiceDebugInfoENS2_9allocatorIS4_EEEE;
- _ZN7android2os16BpServiceManager20getDeclaredInstancesERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_6vectorIS8_NS6_IS8_EEEE;
- _ZN7android2os16BpServiceManager20tryUnregisterServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager22registerClientCallbackERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEERKNSB_INS0_15IClientCallbackEEE;
- _ZN7android2os16BpServiceManager24registerForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManager26unregisterForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManagerC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManagerC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback10descriptorE;
- _ZN7android2os16IServiceCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback12default_implE;
- _ZN7android2os16IServiceCallback14getDefaultImplEv;
- _ZN7android2os16IServiceCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os16IServiceCallbackC2Ev;
- _ZN7android2os16IServiceCallbackD0Ev;
- _ZN7android2os16IServiceCallbackD1Ev;
- _ZN7android2os16IServiceCallbackD2Ev;
- _ZN7android2os16ParcelableHolder14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os16ServiceDebugInfo14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os17BnServiceCallbackC2Ev;
- _ZN7android2os17BpServiceCallback14onRegistrationERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17PersistableBundle10putBooleanERKNS_8String16Eb;
- _ZN7android2os17PersistableBundle12putIntVectorERKNS_8String16ERKNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZN7android2os17PersistableBundle13putLongVectorERKNS_8String16ERKNSt3__16vectorIxNS5_9allocatorIxEEEE;
- _ZN7android2os17PersistableBundle14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17PersistableBundle15putDoubleVectorERKNS_8String16ERKNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZN7android2os17PersistableBundle15putStringVectorERKNS_8String16ERKNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZN7android2os17PersistableBundle16putBooleanVectorERKNS_8String16ERKNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZN7android2os17PersistableBundle19readFromParcelInnerEPKNS_6ParcelEj;
- _ZN7android2os17PersistableBundle20putPersistableBundleERKNS_8String16ERKS1_;
- _ZN7android2os17PersistableBundle5eraseERKNS_8String16E;
- _ZN7android2os17PersistableBundle6putIntERKNS_8String16Ei;
- _ZN7android2os17PersistableBundle7putLongERKNS_8String16Ex;
- _ZN7android2os17PersistableBundle9putDoubleERKNS_8String16Ed;
- _ZN7android2os17PersistableBundle9putStringERKNS_8String16ES4_;
- _ZN7android2os20ParcelFileDescriptor14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os20ParcelFileDescriptorC1ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC1Ev;
- _ZN7android2os20ParcelFileDescriptorC2ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC2Ev;
- _ZN7android2os20ParcelFileDescriptorD0Ev;
- _ZN7android2os20ParcelFileDescriptorD1Ev;
- _ZN7android2os20ParcelFileDescriptorD2Ev;
- _ZN7android4aerrE;
- _ZN7android4alogE;
- _ZN7android4aoutE;
- _ZN7android6binder20LazyServiceRegistrar10reRegisterEv;
- _ZN7android6binder20LazyServiceRegistrar11getInstanceEv;
- _ZN7android6binder20LazyServiceRegistrar12forcePersistEb;
- _ZN7android6binder20LazyServiceRegistrar13tryUnregisterEv;
- _ZN7android6binder20LazyServiceRegistrar15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEbi;
- _ZN7android6binder20LazyServiceRegistrar25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder20LazyServiceRegistrarC1Ev;
- _ZN7android6binder20LazyServiceRegistrarC2Ev;
- _ZN7android6binder6Status11fromStatusTEi;
- _ZN7android6binder6Status12setExceptionEiRKNS_7String8E;
- _ZN7android6binder6Status14readFromParcelERKNS_6ParcelE;
- _ZN7android6binder6Status14setFromStatusTEi;
- _ZN7android6binder6Status17exceptionToStringEi;
- _ZN7android6binder6Status17fromExceptionCodeEi;
- _ZN7android6binder6Status17fromExceptionCodeEiPKc;
- _ZN7android6binder6Status17fromExceptionCodeEiRKNS_7String8E;
- _ZN7android6binder6Status23setServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status24fromServiceSpecificErrorEi;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiPKc;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status2okEv;
- _ZN7android6binder6StatusC1Eii;
- _ZN7android6binder6StatusC1EiiRKNS_7String8E;
- _ZN7android6binder6StatusC2Eii;
- _ZN7android6binder6StatusC2EiiRKNS_7String8E;
- _ZN7android6binder8internal21ClientCounterCallback10reRegisterEv;
- _ZN7android6binder8internal21ClientCounterCallback12forcePersistEb;
- _ZN7android6binder8internal21ClientCounterCallback13tryUnregisterEv;
- _ZN7android6binder8internal21ClientCounterCallback15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEbi;
- _ZN7android6binder8internal21ClientCounterCallback25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder8internal21ClientCounterCallbackC1Ev;
- _ZN7android6binder8internal21ClientCounterCallbackC2Ev;
- _ZN7android6Parcel10appendFromEPKS0_jj;
- _ZN7android6Parcel10markForRpcERKNS_2spINS_10RpcSessionEEE;
- _ZN7android6Parcel10writeFloatEf;
- _ZN7android6Parcel10writeInt32Ei;
- _ZN7android6Parcel10writeInt64Ex;
- _ZN7android6Parcel11compareDataERKS0_;
- _ZN7android6Parcel11finishWriteEj;
- _ZN7android6Parcel11setDataSizeEj;
- _ZN7android6Parcel11writeDoubleEd;
- _ZN7android6Parcel11writeObjectERK18flat_binder_objectb;
- _ZN7android6Parcel11writeUint32Ej;
- _ZN7android6Parcel11writeUint64Ey;
- _ZN7android6Parcel12pushAllowFdsEb;
- _ZN7android6Parcel12restartWriteEj;
- _ZN7android6Parcel12writeCStringEPKc;
- _ZN7android6Parcel12writeInplaceEj;
- _ZN7android6Parcel12writePointerEj;
- _ZN7android6Parcel12writeString8EPKcj;
- _ZN7android6Parcel12writeString8ERKNS_7String8E;
- _ZN7android6Parcel13continueWriteEj;
- _ZN7android6Parcel13flattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13markForBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13writeString16EPKDsj;
- _ZN7android6Parcel13writeString16ERKNS_8String16E;
- _ZN7android6Parcel13writeString16ERKNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZN7android6Parcel13writeString16ERKNSt3__18optionalINS_8String16EEE;
- _ZN7android6Parcel13writeUnpaddedEPKvj;
- _ZN7android6Parcel14acquireObjectsEv;
- _ZN7android6Parcel14freeDataNoInitEv;
- _ZN7android6Parcel14releaseObjectsEv;
- _ZN7android6Parcel14writeByteArrayEjPKh;
- _ZN7android6Parcel15restoreAllowFdsEb;
- _ZN7android6Parcel15setDataCapacityEj;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZN7android6Parcel15writeInt32ArrayEjPKi;
- _ZN7android6Parcel15writeParcelableERKNS_10ParcelableE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__110unique_ptrINS1_6vectorIxNS1_9allocatorIxEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__16vectorIxNS1_9allocatorIxEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__18optionalINS1_6vectorIxNS1_9allocatorIxEEEEEE;
- _ZN7android6Parcel16writeNoExceptionEv;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZN7android6Parcel17writeNativeHandleEPK13native_handle;
- _ZN7android6Parcel17writeStrongBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__110unique_ptrINS1_6vectorIyNS1_9allocatorIyEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__16vectorIyNS1_9allocatorIyEEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__18optionalINS1_6vectorIyNS1_9allocatorIyEEEEEE;
- _ZN7android6Parcel18getGlobalAllocSizeEv;
- _ZN7android6Parcel19finishFlattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel19getGlobalAllocCountEv;
- _ZN7android6Parcel19ipcSetDataReferenceEPKhjPKyjPFvPS0_S2_jS4_jE;
- _ZN7android6Parcel19writeFileDescriptorEib;
- _ZN7android6Parcel19writeInterfaceTokenEPKDsj;
- _ZN7android6Parcel19writeInterfaceTokenERKNS_8String16E;
- _ZN7android6Parcel19writeString16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZN7android6Parcel20closeFileDescriptorsEv;
- _ZN7android6Parcel22writeDupFileDescriptorEi;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZN7android6Parcel25writeParcelFileDescriptorEib;
- _ZN7android6Parcel25writeUniqueFileDescriptorERKNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android6Parcel26writeRawNullableParcelableEPKNS_10ParcelableE;
- _ZN7android6Parcel27replaceCallingWorkSourceUidEj;
- _ZN7android6Parcel28writeDupParcelFileDescriptorEi;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZN7android6Parcel35writeDupImmutableBlobFileDescriptorEi;
- _ZN7android6Parcel4Blob4initEiPvjb;
- _ZN7android6Parcel4Blob5clearEv;
- _ZN7android6Parcel4Blob7releaseEv;
- _ZN7android6Parcel4BlobC1Ev;
- _ZN7android6Parcel4BlobC2Ev;
- _ZN7android6Parcel4BlobD1Ev;
- _ZN7android6Parcel4BlobD2Ev;
- _ZN7android6Parcel5writeEPKvj;
- _ZN7android6Parcel5writeERKNS0_26FlattenableHelperInterfaceE;
- _ZN7android6Parcel7setDataEPKhj;
- _ZN7android6Parcel8freeDataEv;
- _ZN7android6Parcel8growDataEj;
- _ZN7android6Parcel8setErrorEi;
- _ZN7android6Parcel9initStateEv;
- _ZN7android6Parcel9writeBlobEjbPNS0_12WritableBlobE;
- _ZN7android6Parcel9writeBoolEb;
- _ZN7android6Parcel9writeByteEa;
- _ZN7android6Parcel9writeCharEDs;
- _ZN7android6ParcelC1Ev;
- _ZN7android6ParcelC2Ev;
- _ZN7android6ParcelD1Ev;
- _ZN7android6ParcelD2Ev;
- _ZN7android7BBinder10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinder10pingBinderEv;
- _ZN7android7BBinder11getDebugPidEv;
- _ZN7android7BBinder11isInheritRtEv;
- _ZN7android7BBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android7BBinder11localBinderEv;
- _ZN7android7BBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android7BBinder12detachObjectEPKv;
- _ZN7android7BBinder12getExtensionEv;
- _ZN7android7BBinder12setExtensionERKNS_2spINS_7IBinderEEE;
- _ZN7android7BBinder12setInheritRtEb;
- _ZN7android7BBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android7BBinder15isRequestingSidEv;
- _ZN7android7BBinder16setRequestingSidEb;
- _ZN7android7BBinder17getOrCreateExtrasEv;
- _ZN7android7BBinder21getMinSchedulerPolicyEv;
- _ZN7android7BBinder21setMinSchedulerPolicyEii;
- _ZN7android7BBinder23getMinSchedulerPriorityEv;
- _ZN7android7BBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinderC1Ev;
- _ZN7android7BBinderC2Ev;
- _ZN7android7BBinderD0Ev;
- _ZN7android7BBinderD1Ev;
- _ZN7android7BBinderD2Ev;
- _ZN7android7content2pm18PackageChangeEvent14readFromParcelEPKNS_6ParcelE;
- _ZN7android7content2pm21IPackageManagerNative10descriptorE;
- _ZN7android7content2pm21IPackageManagerNative11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm21IPackageManagerNative12default_implE;
- _ZN7android7content2pm21IPackageManagerNative14getDefaultImplEv;
- _ZN7android7content2pm21IPackageManagerNative14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm21IPackageManagerNativeC2Ev;
- _ZN7android7content2pm21IPackageManagerNativeD0Ev;
- _ZN7android7content2pm21IPackageManagerNativeD1Ev;
- _ZN7android7content2pm21IPackageManagerNativeD2Ev;
- _ZN7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm22BnPackageManagerNativeC2Ev;
- _ZN7android7content2pm22BpPackageManagerNative14getAllPackagesEPNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative15getNamesForUidsERKNSt3__16vectorIiNS3_9allocatorIiEEEEPNS4_INS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEENS5_ISE_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative16getLocationFlagsERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPi;
- _ZN7android7content2pm22BpPackageManagerNative16hasSystemFeatureERKNS_8String16EiPb;
- _ZN7android7content2pm22BpPackageManagerNative19isPackageDebuggableERKNS_8String16EPb;
- _ZN7android7content2pm22BpPackageManagerNative22getInstallerForPackageERKNS_8String16EPNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative24getVersionCodeForPackageERKNS_8String16EPx;
- _ZN7android7content2pm22BpPackageManagerNative27hasSha256SigningCertificateERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEERKNS3_6vectorIhNS7_IhEEEEPb;
- _ZN7android7content2pm22BpPackageManagerNative28getModuleMetadataPackageNameEPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29getTargetSdkVersionForPackageERKNS_8String16EPi;
- _ZN7android7content2pm22BpPackageManagerNative29isAudioPlaybackCaptureAllowedERKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEPNS4_IbNS8_IbEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29registerPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNative31unregisterPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver10descriptorE;
- _ZN7android7content2pm22IPackageChangeObserver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver12default_implE;
- _ZN7android7content2pm22IPackageChangeObserver14getDefaultImplEv;
- _ZN7android7content2pm22IPackageChangeObserver14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm22IPackageChangeObserverC2Ev;
- _ZN7android7content2pm22IPackageChangeObserverD0Ev;
- _ZN7android7content2pm22IPackageChangeObserverD1Ev;
- _ZN7android7content2pm22IPackageChangeObserverD2Ev;
- _ZN7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm23BnPackageChangeObserverC2Ev;
- _ZN7android7content2pm23BpPackageChangeObserver16onPackageChangedERKNS1_18PackageChangeEventE;
- _ZN7android7content2pm23BpPackageChangeObserverC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm23BpPackageChangeObserverC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7HexDumpC1EPKvjj;
- _ZN7android7HexDumpC2EPKvjj;
- _ZN7android7IBinder11getDebugPidEPi;
- _ZN7android7IBinder11localBinderEv;
- _ZN7android7IBinder12getExtensionEPNS_2spIS0_EE;
- _ZN7android7IBinder12remoteBinderEv;
- _ZN7android7IBinder12shellCommandERKNS_2spIS0_EEiiiRNS_6VectorINS_8String16EEERKNS1_INS_14IShellCallbackEEERKNS1_INS_15IResultReceiverEEE;
- _ZN7android7IBinder19queryLocalInterfaceERKNS_8String16E;
- _ZN7android7IBinderC2Ev;
- _ZN7android7IBinderD0Ev;
- _ZN7android7IBinderD1Ev;
- _ZN7android7IBinderD2Ev;
- _ZN7android7IMemory10descriptorE;
- _ZN7android7IMemory11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7IMemory12default_implE;
- _ZN7android7IMemory14getDefaultImplEv;
- _ZN7android7IMemory14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android7IMemoryC2Ev;
- _ZN7android7IMemoryD0Ev;
- _ZN7android7IMemoryD1Ev;
- _ZN7android7IMemoryD2Ev;
- _ZN7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BnMemoryC2Ev;
- _ZN7android8BnMemoryD0Ev;
- _ZN7android8BnMemoryD1Ev;
- _ZN7android8BnMemoryD2Ev;
- _ZN7android8BpBinder10onFirstRefEv;
- _ZN7android8BpBinder10pingBinderEv;
- _ZN7android8BpBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android8BpBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android8BpBinder12detachObjectEPKv;
- _ZN7android8BpBinder12remoteBinderEv;
- _ZN7android8BpBinder12sendObituaryEv;
- _ZN7android8BpBinder12sTrackingMapE;
- _ZN7android8BpBinder13getCountByUidERNS_6VectorIjEES3_;
- _ZN7android8BpBinder13ObjectManager4killEv;
- _ZN7android8BpBinder13ObjectManager6attachEPKvPvS4_PFvS3_S4_S4_E;
- _ZN7android8BpBinder13ObjectManager6detachEPKv;
- _ZN7android8BpBinder13ObjectManagerC1Ev;
- _ZN7android8BpBinder13ObjectManagerC2Ev;
- _ZN7android8BpBinder13ObjectManagerD1Ev;
- _ZN7android8BpBinder13ObjectManagerD2Ev;
- _ZN7android8BpBinder13sTrackingLockE;
- _ZN7android8BpBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android8BpBinder14reportOneDeathERKNS0_8ObituaryE;
- _ZN7android8BpBinder14sLimitCallbackE;
- _ZN7android8BpBinder15onLastStrongRefEPKv;
- _ZN7android8BpBinder15sNumTrackedUidsE;
- _ZN7android8BpBinder16enableCountByUidEv;
- _ZN7android8BpBinder16setLimitCallbackEPFviE;
- _ZN7android8BpBinder17disableCountByUidEv;
- _ZN7android8BpBinder18sCountByUidEnabledE;
- _ZN7android8BpBinder19getBinderProxyCountEj;
- _ZN7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZN7android8BpBinder20setCountByUidEnabledEb;
- _ZN7android8BpBinder26sBinderProxyThrottleCreateE;
- _ZN7android8BpBinder29sBinderProxyCountLowWatermarkE;
- _ZN7android8BpBinder29setBinderProxyCountWatermarksEii;
- _ZN7android8BpBinder30sBinderProxyCountHighWatermarkE;
- _ZN7android8BpBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android8BpBinder6createEi;
- _ZN7android8BpBinder6createERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BpBinderC1EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC1EONS0_9RpcHandleE;
- _ZN7android8BpBinderC1EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderC2EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC2EONS0_9RpcHandleE;
- _ZN7android8BpBinderC2EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderD0Ev;
- _ZN7android8BpBinderD1Ev;
- _ZN7android8BpBinderD2Ev;
- _ZN7android8BpMemoryC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryD0Ev;
- _ZN7android8BpMemoryD1Ev;
- _ZN7android8BpMemoryD2Ev;
- _ZN7android8internal9Stability11getCategoryEPNS_7IBinderE;
- _ZN7android8internal9Stability11levelStringENS1_5LevelE;
- _ZN7android8internal9Stability13getLocalLevelEv;
- _ZN7android8internal9Stability15isDeclaredLevelENS1_5LevelE;
- _ZN7android8internal9Stability17debugLogStabilityERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability19markCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability22tryMarkCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability24requiresVintfDeclarationERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability25forceDowngradeToStabilityERKNS_2spINS_7IBinderEEENS1_5LevelE;
- _ZN7android8internal9Stability30forceDowngradeToLocalStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToSystemStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToVendorStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability5checkENS1_8CategoryENS1_5LevelE;
- _ZN7android8internal9Stability7setReprEPNS_7IBinderEij;
- _ZN7android8internal9Stability8Category11debugStringEv;
- _ZN7android8internal9Stability8markVndkEPNS_7IBinderE;
- _ZN7android8internal9Stability9markVintfEPNS_7IBinderE;
- _ZN7android8RpcState11CommandDataC1Ej;
- _ZN7android8RpcState11CommandDataC2Ej;
- _ZN7android8RpcState12countBindersEv;
- _ZN7android8RpcState12getSessionIdERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPi;
- _ZN7android8RpcState12waitForReplyERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPNS_6ParcelE;
- _ZN7android8RpcState13getMaxThreadsERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPj;
- _ZN7android8RpcState13getRootObjectERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState13sendDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressE;
- _ZN7android8RpcState15onBinderLeavingERKNS_2spINS_10RpcSessionEEERKNS1_INS_7IBinderEEEPNS_10RpcAddressE;
- _ZN7android8RpcState15processTransactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState16onBinderEnteringERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8RpcState16processDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState20getAndExecuteCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState20processServerCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState23processTransactInternalERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEENS0_11CommandDataE;
- _ZN7android8RpcState4dumpEv;
- _ZN7android8RpcState6rpcRecERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPvj;
- _ZN7android8RpcState7rpcSendERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPKvj;
- _ZN7android8RpcState8transactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressEjRKNS_6ParcelERKNS_2spINS_10RpcSessionEEEPSA_j;
- _ZN7android8RpcState9terminateEv;
- _ZN7android8RpcStateC1Ev;
- _ZN7android8RpcStateC2Ev;
- _ZN7android8RpcStateD1Ev;
- _ZN7android8RpcStateD2Ev;
- _ZN7android9BpRefBase10onFirstRefEv;
- _ZN7android9BpRefBase15onLastStrongRefEPKv;
- _ZN7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZN7android9BpRefBaseC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseD0Ev;
- _ZN7android9BpRefBaseD1Ev;
- _ZN7android9BpRefBaseD2Ev;
- _ZN7android9HeapCache10binderDiedERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCache10dump_heapsEv;
- _ZN7android9HeapCache8get_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9find_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCacheC1Ev;
- _ZN7android9HeapCacheC2Ev;
- _ZN7android9HeapCacheD0Ev;
- _ZN7android9HeapCacheD1Ev;
- _ZN7android9HeapCacheD2Ev;
- _ZN7android9hexStringEPKvj;
- _ZN7android9RpcServer12listSessionsEv;
- _ZN7android9RpcServer13getMaxThreadsEv;
- _ZN7android9RpcServer13getRootObjectEv;
- _ZN7android9RpcServer13releaseServerEv;
- _ZN7android9RpcServer13setMaxThreadsEj;
- _ZN7android9RpcServer13setRootObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android9RpcServer15setupInetServerEjPj;
- _ZN7android9RpcServer16setupVsockServerEj;
- _ZN7android9RpcServer17setRootObjectWeakERKNS_2wpINS_7IBinderEEE;
- _ZN7android9RpcServer17setupSocketServerERKNS_16RpcSocketAddressE;
- _ZN7android9RpcServer19establishConnectionEONS_2spIS0_EENS_4base14unique_fd_implINS4_13DefaultCloserEEE;
- _ZN7android9RpcServer19setupExternalServerENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android9RpcServer20onSessionTerminatingERKNS_2spINS_10RpcSessionEEE;
- _ZN7android9RpcServer21setupUnixDomainServerEPKc;
- _ZN7android9RpcServer24numUninitializedSessionsEv;
- _ZN7android9RpcServer4joinEv;
- _ZN7android9RpcServer4makeEv;
- _ZN7android9RpcServer61iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProductionEv;
- _ZN7android9RpcServer9acceptOneEv;
- _ZN7android9RpcServer9hasServerEv;
- _ZN7android9RpcServerC1Ev;
- _ZN7android9RpcServerC2Ev;
- _ZN7android9RpcServerD0Ev;
- _ZN7android9RpcServerD1Ev;
- _ZN7android9RpcServerD2Ev;
- _ZN7android9SingletonINS_15PermissionCacheEE11getInstanceEv;
- _ZN7android9SingletonINS_15PermissionCacheEE11hasInstanceEv;
- _ZN7android9SingletonINS_15PermissionCacheEE5sLockE;
- _ZN7android9SingletonINS_15PermissionCacheEE9sInstanceE;
- _ZN7android9SingletonINS_15PermissionCacheEEC1Ev;
- _ZN7android9SingletonINS_15PermissionCacheEEC2Ev;
- _ZN7android9SingletonINS_15PermissionCacheEED1Ev;
- _ZN7android9SingletonINS_15PermissionCacheEED2Ev;
- _ZN7androidlsERNS_10TextOutputERKNS_7HexDumpE;
- _ZN7androidlsERNS_10TextOutputERKNS_8TypeCodeE;
- _ZN7androidlsIA15_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA24_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA2_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA34_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA3_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA43_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA4_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA5_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA8_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA9_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIjEERNS_10TextOutputES2_RKT_;
- _ZN7androidlsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERNS_10TextOutputES9_RKT_;
- _ZN7androidlsIPcEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIPvEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIyEERNS_10TextOutputES2_RKT_;
- _ZNK7android10MemoryBase9getMemoryEPiPj;
- _ZNK7android10RpcAddress13writeToParcelEPNS_6ParcelE;
- _ZNK7android10RpcAddress15viewRawEmbeddedEv;
- _ZNK7android10RpcAddress6isZeroEv;
- _ZNK7android10RpcAddress8toStringEv;
- _ZNK7android10RpcAddressltERKS0_;
- _ZNK7android11IMemoryHeap22getInterfaceDescriptorEv;
- _ZNK7android12BpMemoryHeap12assertMappedEv;
- _ZNK7android12BpMemoryHeap18assertReallyMappedEv;
- _ZNK7android12BpMemoryHeap7getBaseEv;
- _ZNK7android12BpMemoryHeap7getSizeEv;
- _ZNK7android12BpMemoryHeap8getFlagsEv;
- _ZNK7android12BpMemoryHeap9getHeapIDEv;
- _ZNK7android12BpMemoryHeap9getOffsetEv;
- _ZNK7android12MemoryDealer4dumpEPKc;
- _ZNK7android12MemoryDealer4heapEv;
- _ZNK7android12MemoryDealer9allocatorEv;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE10do_compareEPKvS5_;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE10do_destroyEPvj;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE12do_constructEPvj;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE15do_move_forwardEPvPKvj;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE16do_move_backwardEPvPKvj;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE7do_copyEPvPKvj;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE8do_splatEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_compareEPKvSA_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_destroyEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE12do_constructEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE15do_move_forwardEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE16do_move_backwardEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE7do_copyEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE8do_splatEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_compareES3_S3_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_destroyEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE12do_constructEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE15do_move_forwardEPvS3_j;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE16do_move_backwardEPvS3_j;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE7do_copyEPvS3_j;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE8do_splatEPvS3_j;
- _ZNK7android12SortedVectorINS_8String16EE10do_compareEPKvS4_;
- _ZNK7android12SortedVectorINS_8String16EE10do_destroyEPvj;
- _ZNK7android12SortedVectorINS_8String16EE12do_constructEPvj;
- _ZNK7android12SortedVectorINS_8String16EE15do_move_forwardEPvPKvj;
- _ZNK7android12SortedVectorINS_8String16EE16do_move_backwardEPvPKvj;
- _ZNK7android12SortedVectorINS_8String16EE7do_copyEPvPKvj;
- _ZNK7android12SortedVectorINS_8String16EE8do_splatEPvPKvj;
- _ZNK7android14IPCThreadState13getCallingPidEv;
- _ZNK7android14IPCThreadState13getCallingSidEv;
- _ZNK7android14IPCThreadState13getCallingUidEv;
- _ZNK7android14IPCThreadState18getCallRestrictionEv;
- _ZNK7android14IPCThreadState19getStrictModePolicyEv;
- _ZNK7android14IPCThreadState22getServingStackPointerEv;
- _ZNK7android14IPCThreadState23getCallingWorkSourceUidEv;
- _ZNK7android14IPCThreadState25shouldPropagateWorkSourceEv;
- _ZNK7android14IPCThreadState29getLastTransactionBinderFlagsEv;
- _ZNK7android14IShellCallback22getInterfaceDescriptorEv;
- _ZNK7android14MemoryHeapBase7getBaseEv;
- _ZNK7android14MemoryHeapBase7getSizeEv;
- _ZNK7android14MemoryHeapBase8getFlagsEv;
- _ZNK7android14MemoryHeapBase9getDeviceEv;
- _ZNK7android14MemoryHeapBase9getHeapIDEv;
- _ZNK7android14MemoryHeapBase9getOffsetEv;
- _ZNK7android15IResultReceiver22getInterfaceDescriptorEv;
- _ZNK7android15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android15PermissionCache5checkEPbRKNS_8String16Ej;
- _ZNK7android18BufferedTextOutput9getBufferEv;
- _ZNK7android18ServiceManagerShim10getServiceERKNS_8String16E;
- _ZNK7android18ServiceManagerShim12checkServiceERKNS_8String16E;
- _ZNK7android21IPermissionController22getInterfaceDescriptorEv;
- _ZNK7android22SimpleBestFitAllocator4dumpEPKc;
- _ZNK7android22SimpleBestFitAllocator4dumpERNS_7String8EPKc;
- _ZNK7android22SimpleBestFitAllocator4sizeEv;
- _ZNK7android22SimpleBestFitAllocator6dump_lEPKc;
- _ZNK7android22SimpleBestFitAllocator6dump_lERNS_7String8EPKc;
- _ZNK7android2os15IClientCallback22getInterfaceDescriptorEv;
- _ZNK7android2os15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android2os16IServiceCallback22getInterfaceDescriptorEv;
- _ZNK7android2os16ParcelableHolder13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os16ServiceDebugInfo13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle10getBooleanERKNS_8String16EPb;
- _ZNK7android2os17PersistableBundle10getIntKeysEv;
- _ZNK7android2os17PersistableBundle11getLongKeysEv;
- _ZNK7android2os17PersistableBundle12getIntVectorERKNS_8String16EPNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZNK7android2os17PersistableBundle13getDoubleKeysEv;
- _ZNK7android2os17PersistableBundle13getLongVectorERKNS_8String16EPNSt3__16vectorIxNS5_9allocatorIxEEEE;
- _ZNK7android2os17PersistableBundle13getStringKeysEv;
- _ZNK7android2os17PersistableBundle13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle14getBooleanKeysEv;
- _ZNK7android2os17PersistableBundle15getDoubleVectorERKNS_8String16EPNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZNK7android2os17PersistableBundle15getStringVectorERKNS_8String16EPNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZNK7android2os17PersistableBundle16getBooleanVectorERKNS_8String16EPNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZNK7android2os17PersistableBundle16getIntVectorKeysEv;
- _ZNK7android2os17PersistableBundle17getLongVectorKeysEv;
- _ZNK7android2os17PersistableBundle18writeToParcelInnerEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle19getDoubleVectorKeysEv;
- _ZNK7android2os17PersistableBundle19getStringVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getBooleanVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getPersistableBundleERKNS_8String16EPS1_;
- _ZNK7android2os17PersistableBundle24getPersistableBundleKeysEv;
- _ZNK7android2os17PersistableBundle4sizeEv;
- _ZNK7android2os17PersistableBundle5emptyEv;
- _ZNK7android2os17PersistableBundle6getIntERKNS_8String16EPi;
- _ZNK7android2os17PersistableBundle7getLongERKNS_8String16EPx;
- _ZNK7android2os17PersistableBundle9getDoubleERKNS_8String16EPd;
- _ZNK7android2os17PersistableBundle9getStringERKNS_8String16EPS2_;
- _ZNK7android2os20ParcelFileDescriptor13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status9toString8Ev;
- _ZNK7android6Parcel10errorCheckEv;
- _ZNK7android6Parcel10ipcObjectsEv;
- _ZNK7android6Parcel10readDoubleEPd;
- _ZNK7android6Parcel10readDoubleEv;
- _ZNK7android6Parcel10readObjectEb;
- _ZNK7android6Parcel10readUint32EPj;
- _ZNK7android6Parcel10readUint32Ev;
- _ZNK7android6Parcel10readUint64EPy;
- _ZNK7android6Parcel10readUint64Ev;
- _ZNK7android6Parcel10scanForFdsEv;
- _ZNK7android6Parcel11ipcDataSizeEv;
- _ZNK7android6Parcel11readCStringEv;
- _ZNK7android6Parcel11readInplaceEj;
- _ZNK7android6Parcel11readPointerEPj;
- _ZNK7android6Parcel11readPointerEv;
- _ZNK7android6Parcel11readString8EPNS_7String8E;
- _ZNK7android6Parcel11readString8Ev;
- _ZNK7android6Parcel12dataCapacityEv;
- _ZNK7android6Parcel12dataPositionEv;
- _ZNK7android6Parcel12objectsCountEv;
- _ZNK7android6Parcel12readString16EPNS_8String16E;
- _ZNK7android6Parcel12readString16EPNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZNK7android6Parcel12readString16EPNSt3__18optionalINS_8String16EEE;
- _ZNK7android6Parcel12readString16Ev;
- _ZNK7android6Parcel13markSensitiveEv;
- _ZNK7android6Parcel14checkInterfaceEPNS_7IBinderE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZNK7android6Parcel14readParcelableEPNS_10ParcelableE;
- _ZNK7android6Parcel15ipcObjectsCountEv;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__110unique_ptrINS1_6vectorIxNS1_9allocatorIxEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__16vectorIxNS1_9allocatorIxEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__18optionalINS1_6vectorIxNS1_9allocatorIxEEEEEE;
- _ZNK7android6Parcel15setDataPositionEj;
- _ZNK7android6Parcel15unflattenBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16enforceInterfaceEPKDsjPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16enforceInterfaceERKNS_8String16EPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZNK7android6Parcel16readNativeHandleEv;
- _ZNK7android6Parcel16readStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16readStrongBinderEv;
- _ZNK7android6Parcel16readStrongBinderINS_2os15IClientCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_2os16IServiceCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_7content2pm22IPackageChangeObserverEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__110unique_ptrINS1_6vectorIyNS1_9allocatorIyEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__16vectorIyNS1_9allocatorIyEEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__18optionalINS1_6vectorIyNS1_9allocatorIyEEEEEE;
- _ZNK7android6Parcel16validateReadDataEj;
- _ZNK7android6Parcel17getBlobAshmemSizeEv;
- _ZNK7android6Parcel17getOpenAshmemSizeEv;
- _ZNK7android6Parcel17readExceptionCodeEv;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZNK7android6Parcel18hasFileDescriptorsEv;
- _ZNK7android6Parcel18readFileDescriptorEv;
- _ZNK7android6Parcel18readString16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZNK7android6Parcel18readString8InplaceEPj;
- _ZNK7android6Parcel19readString16InplaceEPj;
- _ZNK7android6Parcel21finishUnflattenBinderERKNS_2spINS_7IBinderEEEPS3_;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZNK7android6Parcel24readCallingWorkSourceUidEv;
- _ZNK7android6Parcel24readNullableStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel24readParcelFileDescriptorEv;
- _ZNK7android6Parcel24readUniqueFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZNK7android6Parcel30readUniqueParcelFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel37updateWorkSourceRequestHeaderPositionEv;
- _ZNK7android6Parcel4dataEv;
- _ZNK7android6Parcel4readEPvj;
- _ZNK7android6Parcel4readERNS0_26FlattenableHelperInterfaceE;
- _ZNK7android6Parcel5printERNS_10TextOutputEj;
- _ZNK7android6Parcel7ipcDataEv;
- _ZNK7android6Parcel8allowFdsEv;
- _ZNK7android6Parcel8dataSizeEv;
- _ZNK7android6Parcel8isForRpcEv;
- _ZNK7android6Parcel8readBlobEjPNS0_12ReadableBlobE;
- _ZNK7android6Parcel8readBoolEPb;
- _ZNK7android6Parcel8readBoolEv;
- _ZNK7android6Parcel8readByteEPa;
- _ZNK7android6Parcel8readByteEv;
- _ZNK7android6Parcel8readCharEPDs;
- _ZNK7android6Parcel8readCharEv;
- _ZNK7android6Parcel9dataAvailEv;
- _ZNK7android6Parcel9readFloatEPf;
- _ZNK7android6Parcel9readFloatEv;
- _ZNK7android6Parcel9readInt32EPi;
- _ZNK7android6Parcel9readInt32Ev;
- _ZNK7android6Parcel9readInt64EPx;
- _ZNK7android6Parcel9readInt64Ev;
- _ZNK7android6VectorIiE10do_destroyEPvj;
- _ZNK7android6VectorIiE12do_constructEPvj;
- _ZNK7android6VectorIiE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIiE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIiE7do_copyEPvPKvj;
- _ZNK7android6VectorIiE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE10do_destroyEPvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE12do_constructEPvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE10do_destroyEPvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE12do_constructEPvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE10do_destroyEPvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE12do_constructEPvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_8String16EE10do_destroyEPvj;
- _ZNK7android6VectorINS_8String16EE12do_constructEPvj;
- _ZNK7android6VectorINS_8String16EE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_8String16EE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_8String16EE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_8String16EE8do_splatEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE10do_destroyEPvj;
- _ZNK7android6VectorIPNS_7BBinderEE12do_constructEPvj;
- _ZNK7android6VectorIPNS_7BBinderEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE7do_copyEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE8do_splatEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE10do_destroyEPvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE12do_constructEPvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE7do_copyEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE8do_splatEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE10do_destroyEPvj;
- _ZNK7android6VectorIPNS_7RefBaseEE12do_constructEPvj;
- _ZNK7android6VectorIPNS_7RefBaseEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE7do_copyEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE8do_splatEPvPKvj;
- _ZNK7android7BBinder10findObjectEPKv;
- _ZNK7android7BBinder13isBinderAliveEv;
- _ZNK7android7BBinder22getInterfaceDescriptorEv;
- _ZNK7android7content2pm18PackageChangeEvent13writeToParcelEPNS_6ParcelE;
- _ZNK7android7content2pm21IPackageManagerNative22getInterfaceDescriptorEv;
- _ZNK7android7content2pm22IPackageChangeObserver22getInterfaceDescriptorEv;
- _ZNK7android7IBinder13checkSubclassEPKv;
- _ZNK7android7IMemory11fastPointerERKNS_2spINS_7IBinderEEEi;
- _ZNK7android7IMemory15unsecurePointerEv;
- _ZNK7android7IMemory22getInterfaceDescriptorEv;
- _ZNK7android7IMemory4sizeEv;
- _ZNK7android7IMemory6offsetEv;
- _ZNK7android7IMemory7pointerEv;
- _ZNK7android8BpBinder10findObjectEPKv;
- _ZNK7android8BpBinder10rpcAddressEv;
- _ZNK7android8BpBinder10rpcSessionEv;
- _ZNK7android8BpBinder11isRpcBinderEv;
- _ZNK7android8BpBinder12binderHandleEv;
- _ZNK7android8BpBinder13isBinderAliveEv;
- _ZNK7android8BpBinder13ObjectManager4findEPKv;
- _ZNK7android8BpBinder18isDescriptorCachedEv;
- _ZNK7android8BpBinder22getInterfaceDescriptorEv;
- _ZNK7android8BpMemory9getMemoryEPiPj;
- _ZTCN7android10AllocationE0_NS_10IInterfaceE;
- _ZTCN7android10AllocationE0_NS_10MemoryBaseE;
- _ZTCN7android10AllocationE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10AllocationE0_NS_7IMemoryE;
- _ZTCN7android10AllocationE0_NS_8BnMemoryE;
- _ZTCN7android10AllocationE4_NS_7BBinderE;
- _ZTCN7android10AllocationE4_NS_7IBinderE;
- _ZTCN7android10MemoryBaseE0_NS_10IInterfaceE;
- _ZTCN7android10MemoryBaseE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10MemoryBaseE0_NS_7IMemoryE;
- _ZTCN7android10MemoryBaseE0_NS_8BnMemoryE;
- _ZTCN7android10MemoryBaseE4_NS_7BBinderE;
- _ZTCN7android10MemoryBaseE4_NS_7IBinderE;
- _ZTCN7android10PoolThreadE0_NS_6ThreadE;
- _ZTCN7android11IMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BnMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BnMemoryHeapE4_NS_7BBinderE;
- _ZTCN7android12BnMemoryHeapE4_NS_7IBinderE;
- _ZTCN7android12BpMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BpMemoryHeapE0_NS_11BpInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BpMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BpMemoryHeapE4_NS_9BpRefBaseE;
- _ZTCN7android14IShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE32_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE32_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android14MemoryHeapBaseE32_NS_11IMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE32_NS_12BnMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE36_NS_7BBinderE;
- _ZTCN7android14MemoryHeapBaseE36_NS_7IBinderE;
- _ZTCN7android15BnShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BnShellCallbackE0_NS_11BnInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BnShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BnShellCallbackE4_NS_7BBinderE;
- _ZTCN7android15BnShellCallbackE4_NS_7IBinderE;
- _ZTCN7android15BpShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BpShellCallbackE0_NS_11BpInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BpShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BpShellCallbackE4_NS_9BpRefBaseE;
- _ZTCN7android15IResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_11BnInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BnResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BnResultReceiverE4_NS_7BBinderE;
- _ZTCN7android16BnResultReceiverE4_NS_7IBinderE;
- _ZTCN7android16BpResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BpResultReceiverE0_NS_11BpInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BpResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BpResultReceiverE4_NS_9BpRefBaseE;
- _ZTCN7android18ServiceManagerShimE0_NS_10IInterfaceE;
- _ZTCN7android18ServiceManagerShimE0_NS_15IServiceManagerE;
- _ZTCN7android21IPermissionControllerE0_NS_10IInterfaceE;
- _ZTCN7android22BnPermissionControllerE0_NS_10IInterfaceE;
- _ZTCN7android22BnPermissionControllerE0_NS_11BnInterfaceINS_21IPermissionControllerEEE;
- _ZTCN7android22BnPermissionControllerE0_NS_21IPermissionControllerE;
- _ZTCN7android22BnPermissionControllerE4_NS_7BBinderE;
- _ZTCN7android22BnPermissionControllerE4_NS_7IBinderE;
- _ZTCN7android22BpPermissionControllerE0_NS_10IInterfaceE;
- _ZTCN7android22BpPermissionControllerE0_NS_11BpInterfaceINS_21IPermissionControllerEEE;
- _ZTCN7android22BpPermissionControllerE0_NS_21IPermissionControllerE;
- _ZTCN7android22BpPermissionControllerE4_NS_9BpRefBaseE;
- _ZTCN7android2os15IClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BnClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS_11BnInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BnClientCallbackE4_NS_7BBinderE;
- _ZTCN7android2os16BnClientCallbackE4_NS_7IBinderE;
- _ZTCN7android2os16BnServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BnServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnServiceManagerE0_NS_11BnInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BnServiceManagerE4_NS_7BBinderE;
- _ZTCN7android2os16BnServiceManagerE4_NS_7IBinderE;
- _ZTCN7android2os16BpClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BpClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpClientCallbackE0_NS_11BpInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BpClientCallbackE4_NS_9BpRefBaseE;
- _ZTCN7android2os16BpServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BpServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpServiceManagerE0_NS_11BpInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BpServiceManagerE4_NS_9BpRefBaseE;
- _ZTCN7android2os16IServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_11BnInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BnServiceCallbackE4_NS_7BBinderE;
- _ZTCN7android2os17BnServiceCallbackE4_NS_7IBinderE;
- _ZTCN7android2os17BpServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_11BpInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BpServiceCallbackE4_NS_9BpRefBaseE;
- _ZTCN7android7BBinderE0_NS_7IBinderE;
- _ZTCN7android7content2pm21IPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_11BnInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE4_NS_7BBinderE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE4_NS_7IBinderE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_11BpInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE4_NS_9BpRefBaseE;
- _ZTCN7android7content2pm22IPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_11BnInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE4_NS_7BBinderE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE4_NS_7IBinderE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_11BpInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE4_NS_9BpRefBaseE;
- _ZTCN7android7IMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BnMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BnMemoryE4_NS_7BBinderE;
- _ZTCN7android8BnMemoryE4_NS_7IBinderE;
- _ZTCN7android8BpBinderE0_NS_7IBinderE;
- _ZTCN7android8BpMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BpMemoryE0_NS_11BpInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BpMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BpMemoryE4_NS_9BpRefBaseE;
- _ZTCN7android9HeapCacheE0_NS_7IBinder14DeathRecipientE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_13basic_istreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_14basic_iostreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE8_NS_13basic_ostreamIcS2_EE;
- _ZThn4_N7android10AllocationD0Ev;
- _ZThn4_N7android10AllocationD1Ev;
- _ZThn4_N7android10MemoryBaseD0Ev;
- _ZThn4_N7android10MemoryBaseD1Ev;
- _ZThn4_N7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android12BnMemoryHeapD0Ev;
- _ZThn4_N7android12BnMemoryHeapD1Ev;
- _ZThn4_N7android12BpMemoryHeapD0Ev;
- _ZThn4_N7android12BpMemoryHeapD1Ev;
- _ZThn4_N7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android22BnPermissionController10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn4_N7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn4_N7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn4_N7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn4_N7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn4_N7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android8BnMemoryD0Ev;
- _ZThn4_N7android8BnMemoryD1Ev;
- _ZThn4_N7android8BpMemoryD0Ev;
- _ZThn4_N7android8BpMemoryD1Ev;
- _ZTTN7android10AllocationE;
- _ZTTN7android10IInterfaceE;
- _ZTTN7android10MemoryBaseE;
- _ZTTN7android10PoolThreadE;
- _ZTTN7android10RpcSessionE;
- _ZTTN7android11IMemoryHeapE;
- _ZTTN7android12BnMemoryHeapE;
- _ZTTN7android12BpMemoryHeapE;
- _ZTTN7android12ProcessStateE;
- _ZTTN7android14IShellCallbackE;
- _ZTTN7android14MemoryHeapBaseE;
- _ZTTN7android15BnShellCallbackE;
- _ZTTN7android15BpShellCallbackE;
- _ZTTN7android15IResultReceiverE;
- _ZTTN7android15IServiceManagerE;
- _ZTTN7android16BnResultReceiverE;
- _ZTTN7android16BpResultReceiverE;
- _ZTTN7android18ServiceManagerShimE;
- _ZTTN7android21IPermissionControllerE;
- _ZTTN7android22BnPermissionControllerE;
- _ZTTN7android22BpPermissionControllerE;
- _ZTTN7android2os15IClientCallbackE;
- _ZTTN7android2os15IServiceManagerE;
- _ZTTN7android2os16BnClientCallbackE;
- _ZTTN7android2os16BnServiceManagerE;
- _ZTTN7android2os16BpClientCallbackE;
- _ZTTN7android2os16BpServiceManagerE;
- _ZTTN7android2os16IServiceCallbackE;
- _ZTTN7android2os17BnServiceCallbackE;
- _ZTTN7android2os17BpServiceCallbackE;
- _ZTTN7android7BBinderE;
- _ZTTN7android7content2pm21IPackageManagerNativeE;
- _ZTTN7android7content2pm22BnPackageManagerNativeE;
- _ZTTN7android7content2pm22BpPackageManagerNativeE;
- _ZTTN7android7content2pm22IPackageChangeObserverE;
- _ZTTN7android7content2pm23BnPackageChangeObserverE;
- _ZTTN7android7content2pm23BpPackageChangeObserverE;
- _ZTTN7android7IBinderE;
- _ZTTN7android7IMemoryE;
- _ZTTN7android8BnMemoryE;
- _ZTTN7android8BpBinderE;
- _ZTTN7android8BpMemoryE;
- _ZTTN7android9BpRefBaseE;
- _ZTTN7android9HeapCacheE;
- _ZTTN7android9RpcServerE;
- _ZTTNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE;
- _ZTv0_n12_N7android10AllocationD0Ev;
- _ZTv0_n12_N7android10AllocationD1Ev;
- _ZTv0_n12_N7android10IInterfaceD0Ev;
- _ZTv0_n12_N7android10IInterfaceD1Ev;
- _ZTv0_n12_N7android10MemoryBaseD0Ev;
- _ZTv0_n12_N7android10MemoryBaseD1Ev;
- _ZTv0_n12_N7android10RpcSessionD0Ev;
- _ZTv0_n12_N7android10RpcSessionD1Ev;
- _ZTv0_n12_N7android11IMemoryHeapD0Ev;
- _ZTv0_n12_N7android11IMemoryHeapD1Ev;
- _ZTv0_n12_N7android12BnMemoryHeapD0Ev;
- _ZTv0_n12_N7android12BnMemoryHeapD1Ev;
- _ZTv0_n12_N7android12BpMemoryHeapD0Ev;
- _ZTv0_n12_N7android12BpMemoryHeapD1Ev;
- _ZTv0_n12_N7android12ProcessStateD0Ev;
- _ZTv0_n12_N7android12ProcessStateD1Ev;
- _ZTv0_n12_N7android14IShellCallbackD0Ev;
- _ZTv0_n12_N7android14IShellCallbackD1Ev;
- _ZTv0_n12_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n12_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n12_N7android15IResultReceiverD0Ev;
- _ZTv0_n12_N7android15IResultReceiverD1Ev;
- _ZTv0_n12_N7android15IServiceManagerD0Ev;
- _ZTv0_n12_N7android15IServiceManagerD1Ev;
- _ZTv0_n12_N7android21IPermissionControllerD0Ev;
- _ZTv0_n12_N7android21IPermissionControllerD1Ev;
- _ZTv0_n12_N7android2os15IClientCallbackD0Ev;
- _ZTv0_n12_N7android2os15IClientCallbackD1Ev;
- _ZTv0_n12_N7android2os15IServiceManagerD0Ev;
- _ZTv0_n12_N7android2os15IServiceManagerD1Ev;
- _ZTv0_n12_N7android2os16IServiceCallbackD0Ev;
- _ZTv0_n12_N7android2os16IServiceCallbackD1Ev;
- _ZTv0_n12_N7android7BBinderD0Ev;
- _ZTv0_n12_N7android7BBinderD1Ev;
- _ZTv0_n12_N7android7content2pm21IPackageManagerNativeD0Ev;
- _ZTv0_n12_N7android7content2pm21IPackageManagerNativeD1Ev;
- _ZTv0_n12_N7android7content2pm22IPackageChangeObserverD0Ev;
- _ZTv0_n12_N7android7content2pm22IPackageChangeObserverD1Ev;
- _ZTv0_n12_N7android7IBinderD0Ev;
- _ZTv0_n12_N7android7IBinderD1Ev;
- _ZTv0_n12_N7android7IMemoryD0Ev;
- _ZTv0_n12_N7android7IMemoryD1Ev;
- _ZTv0_n12_N7android8BnMemoryD0Ev;
- _ZTv0_n12_N7android8BnMemoryD1Ev;
- _ZTv0_n12_N7android8BpBinderD0Ev;
- _ZTv0_n12_N7android8BpBinderD1Ev;
- _ZTv0_n12_N7android8BpMemoryD0Ev;
- _ZTv0_n12_N7android8BpMemoryD1Ev;
- _ZTv0_n12_N7android9BpRefBaseD0Ev;
- _ZTv0_n12_N7android9BpRefBaseD1Ev;
- _ZTv0_n12_N7android9HeapCacheD0Ev;
- _ZTv0_n12_N7android9HeapCacheD1Ev;
- _ZTv0_n12_N7android9RpcServerD0Ev;
- _ZTv0_n12_N7android9RpcServerD1Ev;
- _ZTv0_n16_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n16_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n16_N7android8BpBinder10onFirstRefEv;
- _ZTv0_n16_N7android9BpRefBase10onFirstRefEv;
- _ZTv0_n20_N7android8BpBinder15onLastStrongRefEPKv;
- _ZTv0_n20_N7android9BpRefBase15onLastStrongRefEPKv;
- _ZTv0_n24_N7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZTv0_n24_N7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZTv0_n28_NK7android14MemoryHeapBase9getHeapIDEv;
- _ZTv0_n32_NK7android14MemoryHeapBase7getBaseEv;
- _ZTv0_n36_NK7android14MemoryHeapBase7getSizeEv;
- _ZTv0_n40_NK7android14MemoryHeapBase8getFlagsEv;
- _ZTv0_n44_NK7android14MemoryHeapBase9getOffsetEv;
- _ZTvn4_n16_N7android14MemoryHeapBaseD0Ev;
- _ZTvn4_n16_N7android14MemoryHeapBaseD1Ev;
- _ZTVN7android10AllocationE;
- _ZTVN7android10IInterfaceE;
- _ZTVN7android10MemoryBaseE;
- _ZTVN7android10PoolThreadE;
- _ZTVN7android10RpcSession13RpcConnectionE;
- _ZTVN7android10RpcSessionE;
- _ZTVN7android10TextOutputE;
- _ZTVN7android11IMemoryHeapE;
- _ZTVN7android12BnMemoryHeapE;
- _ZTVN7android12BpMemoryHeapE;
- _ZTVN7android12FdTextOutputE;
- _ZTVN7android12MemoryDealerE;
- _ZTVN7android12ProcessStateE;
- _ZTVN7android12SortedVectorINS_15PermissionCache5EntryEEE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEEE;
- _ZTVN7android12SortedVectorINS_8String16EEE;
- _ZTVN7android13LogTextOutputE;
- _ZTVN7android14IShellCallbackE;
- _ZTVN7android14MemoryHeapBaseE;
- _ZTVN7android15BnShellCallbackE;
- _ZTVN7android15BpShellCallbackE;
- _ZTVN7android15IResultReceiverE;
- _ZTVN7android15IServiceManagerE;
- _ZTVN7android16BnResultReceiverE;
- _ZTVN7android16BpResultReceiverE;
- _ZTVN7android17InetSocketAddressE;
- _ZTVN7android17UnixSocketAddressE;
- _ZTVN7android18BufferedTextOutput11BufferStateE;
- _ZTVN7android18BufferedTextOutputE;
- _ZTVN7android18ServiceManagerShimE;
- _ZTVN7android18VsockSocketAddressE;
- _ZTVN7android21IPermissionControllerE;
- _ZTVN7android22BnPermissionControllerE;
- _ZTVN7android22BpPermissionControllerE;
- _ZTVN7android2os15IClientCallbackE;
- _ZTVN7android2os15IServiceManagerE;
- _ZTVN7android2os16BnClientCallbackE;
- _ZTVN7android2os16BnServiceManagerE;
- _ZTVN7android2os16BpClientCallbackE;
- _ZTVN7android2os16BpServiceManagerE;
- _ZTVN7android2os16IServiceCallbackE;
- _ZTVN7android2os16ParcelableHolderE;
- _ZTVN7android2os16ServiceDebugInfoE;
- _ZTVN7android2os17BnServiceCallbackE;
- _ZTVN7android2os17BpServiceCallbackE;
- _ZTVN7android2os17PersistableBundleE;
- _ZTVN7android2os20ParcelFileDescriptorE;
- _ZTVN7android6VectorIiEE;
- _ZTVN7android6VectorINS_12ProcessState12handle_entryEEE;
- _ZTVN7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEEE;
- _ZTVN7android6VectorINS_8BpBinder8ObituaryEEE;
- _ZTVN7android6VectorINS_8String16EEE;
- _ZTVN7android6VectorIPNS_7BBinderEEE;
- _ZTVN7android6VectorIPNS_7RefBase12weakref_typeEEE;
- _ZTVN7android6VectorIPNS_7RefBaseEEE;
- _ZTVN7android7BBinderE;
- _ZTVN7android7content2pm18PackageChangeEventE;
- _ZTVN7android7content2pm21IPackageManagerNativeE;
- _ZTVN7android7content2pm22BnPackageManagerNativeE;
- _ZTVN7android7content2pm22BpPackageManagerNativeE;
- _ZTVN7android7content2pm22IPackageChangeObserverE;
- _ZTVN7android7content2pm23BnPackageChangeObserverE;
- _ZTVN7android7content2pm23BpPackageChangeObserverE;
- _ZTVN7android7IBinderE;
- _ZTVN7android7IMemoryE;
- _ZTVN7android8BnMemoryE;
- _ZTVN7android8BpBinderE;
- _ZTVN7android8BpMemoryE;
- _ZTVN7android9BpRefBaseE;
- _ZTVN7android9HeapCacheE;
- _ZTVN7android9RpcServerE;
- local:
- *;
-};
diff --git a/libs/binder/libbinder.arm32.vendor.map b/libs/binder/libbinder.arm32.vendor.map
deleted file mode 100644
index 5042414..0000000
--- a/libs/binder/libbinder.arm32.vendor.map
+++ /dev/null
@@ -1,1319 +0,0 @@
-# b/190148312: Populate with correct list of ABI symbols
-LIBBINDER {
- global:
- getBinderKernelReferences;
- kDefaultDriver;
- _ZN7android10AllocationC1ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEEij;
- _ZN7android10AllocationC2ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEEij;
- _ZN7android10AllocationD0Ev;
- _ZN7android10AllocationD1Ev;
- _ZN7android10AllocationD2Ev;
- _ZN7android10IInterface8asBinderEPKS0_;
- _ZN7android10IInterface8asBinderERKNS_2spIS0_EE;
- _ZN7android10IInterfaceC2Ev;
- _ZN7android10IInterfaceD0Ev;
- _ZN7android10IInterfaceD1Ev;
- _ZN7android10IInterfaceD2Ev;
- _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij;
- _ZN7android10MemoryBaseC2ERKNS_2spINS_11IMemoryHeapEEEij;
- _ZN7android10MemoryBaseD0Ev;
- _ZN7android10MemoryBaseD1Ev;
- _ZN7android10MemoryBaseD2Ev;
- _ZN7android10RpcAddress14readFromParcelERKNS_6ParcelE;
- _ZN7android10RpcAddress15fromRawEmbeddedEPKNS_14RpcWireAddressE;
- _ZN7android10RpcAddress4zeroEv;
- _ZN7android10RpcAddress6uniqueEv;
- _ZN7android10RpcAddressC1Ev;
- _ZN7android10RpcAddressC2Ev;
- _ZN7android10RpcAddressD1Ev;
- _ZN7android10RpcAddressD2Ev;
- _ZN7android10RpcSession12setForServerERKNS_2wpINS_9RpcServerEEEi;
- _ZN7android10RpcSession13getRootObjectEv;
- _ZN7android10RpcSession13sendDecStrongERKNS_10RpcAddressE;
- _ZN7android10RpcSession15setupInetClientEPKcj;
- _ZN7android10RpcSession15terminateLockedEv;
- _ZN7android10RpcSession16setupVsockClientEjj;
- _ZN7android10RpcSession17setupSocketClientERKNS_16RpcSocketAddressE;
- _ZN7android10RpcSession19addClientConnectionENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession19ExclusiveConnection14findConnectionEiPNS_2spINS0_13RpcConnectionEEES5_RNSt3__16vectorIS4_NS6_9allocatorIS4_EEEEj;
- _ZN7android10RpcSession19ExclusiveConnectionC1ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionC2ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionD1Ev;
- _ZN7android10RpcSession19ExclusiveConnectionD2Ev;
- _ZN7android10RpcSession19getRemoteMaxThreadsEPj;
- _ZN7android10RpcSession20setupOneSocketClientERKNS_16RpcSocketAddressEi;
- _ZN7android10RpcSession21setupUnixDomainClientEPKc;
- _ZN7android10RpcSession22addNullDebuggingClientEv;
- _ZN7android10RpcSession22removeServerConnectionERKNS_2spINS0_13RpcConnectionEEE;
- _ZN7android10RpcSession24assignServerToThisThreadENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4joinENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4makeEv;
- _ZN7android10RpcSession6readIdEv;
- _ZN7android10RpcSession6serverEv;
- _ZN7android10RpcSession7preJoinENSt3__16threadE;
- _ZN7android10RpcSession8transactERKNS_10RpcAddressEjRKNS_6ParcelEPS4_j;
- _ZN7android10RpcSessionC1Ev;
- _ZN7android10RpcSessionC2Ev;
- _ZN7android10RpcSessionD0Ev;
- _ZN7android10RpcSessionD1Ev;
- _ZN7android10RpcSessionD2Ev;
- _ZN7android10TextOutputC2Ev;
- _ZN7android10TextOutputD0Ev;
- _ZN7android10TextOutputD1Ev;
- _ZN7android10TextOutputD2Ev;
- _ZN7android10zeroMemoryEPhj;
- _ZN7android11BnInterfaceINS_11IMemoryHeapEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_14IShellCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_15IResultReceiverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IClientCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IServiceManagerEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os16IServiceCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm21IPackageManagerNativeEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm22IPackageChangeObserverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7IMemoryEE10onAsBinderEv;
- _ZN7android11IMemoryHeap10descriptorE;
- _ZN7android11IMemoryHeap11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android11IMemoryHeap12default_implE;
- _ZN7android11IMemoryHeap14getDefaultImplEv;
- _ZN7android11IMemoryHeap14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android11IMemoryHeapC2Ev;
- _ZN7android11IMemoryHeapD0Ev;
- _ZN7android11IMemoryHeapD1Ev;
- _ZN7android11IMemoryHeapD2Ev;
- _ZN7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android12BnMemoryHeapC2Ev;
- _ZN7android12BnMemoryHeapD0Ev;
- _ZN7android12BnMemoryHeapD1Ev;
- _ZN7android12BnMemoryHeapD2Ev;
- _ZN7android12BpMemoryHeapC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapD0Ev;
- _ZN7android12BpMemoryHeapD1Ev;
- _ZN7android12BpMemoryHeapD2Ev;
- _ZN7android12gTextBuffersE;
- _ZN7android12MemoryDealer10deallocateEj;
- _ZN7android12MemoryDealer22getAllocationAlignmentEv;
- _ZN7android12MemoryDealer8allocateEj;
- _ZN7android12MemoryDealerC1EjPKcj;
- _ZN7android12MemoryDealerC2EjPKcj;
- _ZN7android12MemoryDealerD0Ev;
- _ZN7android12MemoryDealerD1Ev;
- _ZN7android12MemoryDealerD2Ev;
- _ZN7android12printHexDataEiPKvjjijbPFvPvPKcES2_;
- _ZN7android12ProcessState10selfOrNullEv;
- _ZN7android12ProcessState13expungeHandleEiPNS_7IBinderE;
- _ZN7android12ProcessState13getDriverNameEv;
- _ZN7android12ProcessState14initWithDriverEPKc;
- _ZN7android12ProcessState15startThreadPoolEv;
- _ZN7android12ProcessState16getContextObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android12ProcessState17spawnPooledThreadEb;
- _ZN7android12ProcessState18giveThreadPoolNameEv;
- _ZN7android12ProcessState18lookupHandleLockedEi;
- _ZN7android12ProcessState18setCallRestrictionENS0_15CallRestrictionE;
- _ZN7android12ProcessState19getKernelReferencesEjPj;
- _ZN7android12ProcessState20becomeContextManagerEv;
- _ZN7android12ProcessState20makeBinderThreadNameEv;
- _ZN7android12ProcessState23getStrongProxyForHandleEi;
- _ZN7android12ProcessState24getStrongRefCountForNodeERKNS_2spINS_8BpBinderEEE;
- _ZN7android12ProcessState25enableOnewaySpamDetectionEb;
- _ZN7android12ProcessState27setThreadPoolMaxThreadCountEj;
- _ZN7android12ProcessState4initEPKcb;
- _ZN7android12ProcessState4selfEv;
- _ZN7android12ProcessStateC1EPKc;
- _ZN7android12ProcessStateC2EPKc;
- _ZN7android12ProcessStateD0Ev;
- _ZN7android12ProcessStateD1Ev;
- _ZN7android12ProcessStateD2Ev;
- _ZN7android13printTypeCodeEjPFvPvPKcES0_;
- _ZN7android14IPCThreadState10freeBufferEPNS_6ParcelEPKhjPKyj;
- _ZN7android14IPCThreadState10selfOrNullEv;
- _ZN7android14IPCThreadState11clearCallerEv;
- _ZN7android14IPCThreadState11stopProcessEb;
- _ZN7android14IPCThreadState12setupPollingEPi;
- _ZN7android14IPCThreadState13decWeakHandleEi;
- _ZN7android14IPCThreadState13expungeHandleEiPNS_7IBinderE;
- _ZN7android14IPCThreadState13flushCommandsEv;
- _ZN7android14IPCThreadState13flushIfNeededEv;
- _ZN7android14IPCThreadState13incWeakHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState14clearLastErrorEv;
- _ZN7android14IPCThreadState14executeCommandEi;
- _ZN7android14IPCThreadState14joinThreadPoolEb;
- _ZN7android14IPCThreadState14talkWithDriverEb;
- _ZN7android14IPCThreadState15decStrongHandleEi;
- _ZN7android14IPCThreadState15incStrongHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi;
- _ZN7android14IPCThreadState16threadDestructorEPv;
- _ZN7android14IPCThreadState18setCallRestrictionENS_12ProcessState15CallRestrictionE;
- _ZN7android14IPCThreadState19setStrictModePolicyEi;
- _ZN7android14IPCThreadState19setTheContextObjectERKNS_2spINS_7BBinderEEE;
- _ZN7android14IPCThreadState20clearCallingIdentityEv;
- _ZN7android14IPCThreadState20getAndExecuteCommandEv;
- _ZN7android14IPCThreadState20getProcessFreezeInfoEiPbS1_;
- _ZN7android14IPCThreadState20handlePolledCommandsEv;
- _ZN7android14IPCThreadState20processPendingDerefsEv;
- _ZN7android14IPCThreadState20writeTransactionDataEijijRKNS_6ParcelEPi;
- _ZN7android14IPCThreadState22attemptIncStrongHandleEi;
- _ZN7android14IPCThreadState22clearCallingWorkSourceEv;
- _ZN7android14IPCThreadState22clearDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState22processPostWriteDerefsEv;
- _ZN7android14IPCThreadState22restoreCallingIdentityEx;
- _ZN7android14IPCThreadState23setCallingWorkSourceUidEj;
- _ZN7android14IPCThreadState24clearPropagateWorkSourceEv;
- _ZN7android14IPCThreadState24requestDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState24restoreCallingWorkSourceEx;
- _ZN7android14IPCThreadState25blockUntilThreadAvailableEv;
- _ZN7android14IPCThreadState27disableBackgroundSchedulingEb;
- _ZN7android14IPCThreadState28backgroundSchedulingDisabledEv;
- _ZN7android14IPCThreadState29setLastTransactionBinderFlagsEi;
- _ZN7android14IPCThreadState41setCallingWorkSourceUidWithoutPropagationEj;
- _ZN7android14IPCThreadState4selfEv;
- _ZN7android14IPCThreadState6freezeEibj;
- _ZN7android14IPCThreadState7processEv;
- _ZN7android14IPCThreadState8shutdownEv;
- _ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j;
- _ZN7android14IPCThreadState9sendReplyERKNS_6ParcelEj;
- _ZN7android14IPCThreadStateC1Ev;
- _ZN7android14IPCThreadStateC2Ev;
- _ZN7android14IPCThreadStateD1Ev;
- _ZN7android14IPCThreadStateD2Ev;
- _ZN7android14IShellCallback10descriptorE;
- _ZN7android14IShellCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android14IShellCallback12default_implE;
- _ZN7android14IShellCallback14getDefaultImplEv;
- _ZN7android14IShellCallback14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android14IShellCallbackC2Ev;
- _ZN7android14IShellCallbackD0Ev;
- _ZN7android14IShellCallbackD1Ev;
- _ZN7android14IShellCallbackD2Ev;
- _ZN7android14MemoryHeapBase4initEiPvjiPKc;
- _ZN7android14MemoryHeapBase5mapfdEibjl;
- _ZN7android14MemoryHeapBase7disposeEv;
- _ZN7android14MemoryHeapBaseC1Eijjl;
- _ZN7android14MemoryHeapBaseC1EjjPKc;
- _ZN7android14MemoryHeapBaseC1EPKcjj;
- _ZN7android14MemoryHeapBaseC1Ev;
- _ZN7android14MemoryHeapBaseC2Eijjl;
- _ZN7android14MemoryHeapBaseC2EjjPKc;
- _ZN7android14MemoryHeapBaseC2EPKcjj;
- _ZN7android14MemoryHeapBaseC2Ev;
- _ZN7android14MemoryHeapBaseD0Ev;
- _ZN7android14MemoryHeapBaseD1Ev;
- _ZN7android14MemoryHeapBaseD2Ev;
- _ZN7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android15IResultReceiver10descriptorE;
- _ZN7android15IResultReceiver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android15IResultReceiver12default_implE;
- _ZN7android15IResultReceiver14getDefaultImplEv;
- _ZN7android15IResultReceiver14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android15IResultReceiverC2Ev;
- _ZN7android15IResultReceiverD0Ev;
- _ZN7android15IResultReceiverD1Ev;
- _ZN7android15IResultReceiverD2Ev;
- _ZN7android15IServiceManagerC2Ev;
- _ZN7android15IServiceManagerD0Ev;
- _ZN7android15IServiceManagerD1Ev;
- _ZN7android15IServiceManagerD2Ev;
- _ZN7android15stringForIndentEi;
- _ZN7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android18BufferedTextOutput10moveIndentEi;
- _ZN7android18BufferedTextOutput10pushBundleEv;
- _ZN7android18BufferedTextOutput5printEPKcj;
- _ZN7android18BufferedTextOutput9popBundleEv;
- _ZN7android18BufferedTextOutputC2Ej;
- _ZN7android18BufferedTextOutputD0Ev;
- _ZN7android18BufferedTextOutputD1Ev;
- _ZN7android18BufferedTextOutputD2Ev;
- _ZN7android18ServiceManagerShim10addServiceERKNS_8String16ERKNS_2spINS_7IBinderEEEbi;
- _ZN7android18ServiceManagerShim10isDeclaredERKNS_8String16E;
- _ZN7android18ServiceManagerShim12listServicesEi;
- _ZN7android18ServiceManagerShim14waitForServiceERKNS_8String16E;
- _ZN7android18ServiceManagerShim16updatableViaApexERKNS_8String16E;
- _ZN7android18ServiceManagerShim20getDeclaredInstancesERKNS_8String16E;
- _ZN7android18ServiceManagerShimC1ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18ServiceManagerShimC2ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18the_context_objectE;
- _ZN7android21defaultServiceManagerEv;
- _ZN7android22SimpleBestFitAllocator10deallocateEj;
- _ZN7android22SimpleBestFitAllocator12kMemoryAlignE;
- _ZN7android22SimpleBestFitAllocator5allocEjj;
- _ZN7android22SimpleBestFitAllocator7deallocEj;
- _ZN7android22SimpleBestFitAllocator8allocateEjj;
- _ZN7android22SimpleBestFitAllocatorC1Ej;
- _ZN7android22SimpleBestFitAllocatorC2Ej;
- _ZN7android22SimpleBestFitAllocatorD1Ev;
- _ZN7android22SimpleBestFitAllocatorD2Ev;
- _ZN7android24setDefaultServiceManagerERKNS_2spINS_15IServiceManagerEEE;
- _ZN7android2os15IClientCallback10descriptorE;
- _ZN7android2os15IClientCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IClientCallback12default_implE;
- _ZN7android2os15IClientCallback14getDefaultImplEv;
- _ZN7android2os15IClientCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IClientCallbackC2Ev;
- _ZN7android2os15IClientCallbackD0Ev;
- _ZN7android2os15IClientCallbackD1Ev;
- _ZN7android2os15IClientCallbackD2Ev;
- _ZN7android2os15IServiceManager10descriptorE;
- _ZN7android2os15IServiceManager11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IServiceManager12default_implE;
- _ZN7android2os15IServiceManager14getDefaultImplEv;
- _ZN7android2os15IServiceManager14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IServiceManagerC2Ev;
- _ZN7android2os15IServiceManagerD0Ev;
- _ZN7android2os15IServiceManagerD1Ev;
- _ZN7android2os15IServiceManagerD2Ev;
- _ZN7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnClientCallbackC2Ev;
- _ZN7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnServiceManagerC2Ev;
- _ZN7android2os16BpClientCallback9onClientsERKNS_2spINS_7IBinderEEEb;
- _ZN7android2os16BpClientCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpClientCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10addServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEEbi;
- _ZN7android2os16BpServiceManager10getServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10isDeclaredERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPb;
- _ZN7android2os16BpServiceManager12checkServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager12listServicesEiPNSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEE;
- _ZN7android2os16BpServiceManager16updatableViaApexERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_8optionalIS8_EE;
- _ZN7android2os16BpServiceManager19getServiceDebugInfoEPNSt3__16vectorINS0_16ServiceDebugInfoENS2_9allocatorIS4_EEEE;
- _ZN7android2os16BpServiceManager20getDeclaredInstancesERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_6vectorIS8_NS6_IS8_EEEE;
- _ZN7android2os16BpServiceManager20tryUnregisterServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager22registerClientCallbackERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEERKNSB_INS0_15IClientCallbackEEE;
- _ZN7android2os16BpServiceManager24registerForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManager26unregisterForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManagerC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManagerC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback10descriptorE;
- _ZN7android2os16IServiceCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback12default_implE;
- _ZN7android2os16IServiceCallback14getDefaultImplEv;
- _ZN7android2os16IServiceCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os16IServiceCallbackC2Ev;
- _ZN7android2os16IServiceCallbackD0Ev;
- _ZN7android2os16IServiceCallbackD1Ev;
- _ZN7android2os16IServiceCallbackD2Ev;
- _ZN7android2os16ParcelableHolder14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os16ServiceDebugInfo14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os17BnServiceCallbackC2Ev;
- _ZN7android2os17BpServiceCallback14onRegistrationERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17PersistableBundle10putBooleanERKNS_8String16Eb;
- _ZN7android2os17PersistableBundle12putIntVectorERKNS_8String16ERKNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZN7android2os17PersistableBundle13putLongVectorERKNS_8String16ERKNSt3__16vectorIxNS5_9allocatorIxEEEE;
- _ZN7android2os17PersistableBundle14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17PersistableBundle15putDoubleVectorERKNS_8String16ERKNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZN7android2os17PersistableBundle15putStringVectorERKNS_8String16ERKNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZN7android2os17PersistableBundle16putBooleanVectorERKNS_8String16ERKNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZN7android2os17PersistableBundle19readFromParcelInnerEPKNS_6ParcelEj;
- _ZN7android2os17PersistableBundle20putPersistableBundleERKNS_8String16ERKS1_;
- _ZN7android2os17PersistableBundle5eraseERKNS_8String16E;
- _ZN7android2os17PersistableBundle6putIntERKNS_8String16Ei;
- _ZN7android2os17PersistableBundle7putLongERKNS_8String16Ex;
- _ZN7android2os17PersistableBundle9putDoubleERKNS_8String16Ed;
- _ZN7android2os17PersistableBundle9putStringERKNS_8String16ES4_;
- _ZN7android2os20ParcelFileDescriptor14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os20ParcelFileDescriptorC1ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC1Ev;
- _ZN7android2os20ParcelFileDescriptorC2ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC2Ev;
- _ZN7android2os20ParcelFileDescriptorD0Ev;
- _ZN7android2os20ParcelFileDescriptorD1Ev;
- _ZN7android2os20ParcelFileDescriptorD2Ev;
- _ZN7android4aerrE;
- _ZN7android4alogE;
- _ZN7android4aoutE;
- _ZN7android6binder20LazyServiceRegistrar10reRegisterEv;
- _ZN7android6binder20LazyServiceRegistrar11getInstanceEv;
- _ZN7android6binder20LazyServiceRegistrar12forcePersistEb;
- _ZN7android6binder20LazyServiceRegistrar13tryUnregisterEv;
- _ZN7android6binder20LazyServiceRegistrar15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEbi;
- _ZN7android6binder20LazyServiceRegistrar25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder20LazyServiceRegistrarC1Ev;
- _ZN7android6binder20LazyServiceRegistrarC2Ev;
- _ZN7android6binder6Status11fromStatusTEi;
- _ZN7android6binder6Status12setExceptionEiRKNS_7String8E;
- _ZN7android6binder6Status14readFromParcelERKNS_6ParcelE;
- _ZN7android6binder6Status14setFromStatusTEi;
- _ZN7android6binder6Status17exceptionToStringEi;
- _ZN7android6binder6Status17fromExceptionCodeEi;
- _ZN7android6binder6Status17fromExceptionCodeEiPKc;
- _ZN7android6binder6Status17fromExceptionCodeEiRKNS_7String8E;
- _ZN7android6binder6Status23setServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status24fromServiceSpecificErrorEi;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiPKc;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status2okEv;
- _ZN7android6binder6StatusC1Eii;
- _ZN7android6binder6StatusC1EiiRKNS_7String8E;
- _ZN7android6binder6StatusC2Eii;
- _ZN7android6binder6StatusC2EiiRKNS_7String8E;
- _ZN7android6binder8internal21ClientCounterCallback10reRegisterEv;
- _ZN7android6binder8internal21ClientCounterCallback12forcePersistEb;
- _ZN7android6binder8internal21ClientCounterCallback13tryUnregisterEv;
- _ZN7android6binder8internal21ClientCounterCallback15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEbi;
- _ZN7android6binder8internal21ClientCounterCallback25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder8internal21ClientCounterCallbackC1Ev;
- _ZN7android6binder8internal21ClientCounterCallbackC2Ev;
- _ZN7android6Parcel10appendFromEPKS0_jj;
- _ZN7android6Parcel10markForRpcERKNS_2spINS_10RpcSessionEEE;
- _ZN7android6Parcel10writeFloatEf;
- _ZN7android6Parcel10writeInt32Ei;
- _ZN7android6Parcel10writeInt64Ex;
- _ZN7android6Parcel11compareDataERKS0_;
- _ZN7android6Parcel11finishWriteEj;
- _ZN7android6Parcel11setDataSizeEj;
- _ZN7android6Parcel11writeDoubleEd;
- _ZN7android6Parcel11writeObjectERK18flat_binder_objectb;
- _ZN7android6Parcel11writeUint32Ej;
- _ZN7android6Parcel11writeUint64Ey;
- _ZN7android6Parcel12pushAllowFdsEb;
- _ZN7android6Parcel12restartWriteEj;
- _ZN7android6Parcel12writeCStringEPKc;
- _ZN7android6Parcel12writeInplaceEj;
- _ZN7android6Parcel12writePointerEj;
- _ZN7android6Parcel12writeString8EPKcj;
- _ZN7android6Parcel12writeString8ERKNS_7String8E;
- _ZN7android6Parcel13continueWriteEj;
- _ZN7android6Parcel13flattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13markForBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13writeString16EPKDsj;
- _ZN7android6Parcel13writeString16ERKNS_8String16E;
- _ZN7android6Parcel13writeString16ERKNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZN7android6Parcel13writeString16ERKNSt3__18optionalINS_8String16EEE;
- _ZN7android6Parcel13writeUnpaddedEPKvj;
- _ZN7android6Parcel14acquireObjectsEv;
- _ZN7android6Parcel14freeDataNoInitEv;
- _ZN7android6Parcel14releaseObjectsEv;
- _ZN7android6Parcel14writeByteArrayEjPKh;
- _ZN7android6Parcel15restoreAllowFdsEb;
- _ZN7android6Parcel15setDataCapacityEj;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZN7android6Parcel15writeInt32ArrayEjPKi;
- _ZN7android6Parcel15writeParcelableERKNS_10ParcelableE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__110unique_ptrINS1_6vectorIxNS1_9allocatorIxEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__16vectorIxNS1_9allocatorIxEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__18optionalINS1_6vectorIxNS1_9allocatorIxEEEEEE;
- _ZN7android6Parcel16writeNoExceptionEv;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZN7android6Parcel17writeNativeHandleEPK13native_handle;
- _ZN7android6Parcel17writeStrongBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__110unique_ptrINS1_6vectorIyNS1_9allocatorIyEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__16vectorIyNS1_9allocatorIyEEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__18optionalINS1_6vectorIyNS1_9allocatorIyEEEEEE;
- _ZN7android6Parcel18getGlobalAllocSizeEv;
- _ZN7android6Parcel19finishFlattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel19getGlobalAllocCountEv;
- _ZN7android6Parcel19ipcSetDataReferenceEPKhjPKyjPFvPS0_S2_jS4_jE;
- _ZN7android6Parcel19writeFileDescriptorEib;
- _ZN7android6Parcel19writeInterfaceTokenEPKDsj;
- _ZN7android6Parcel19writeInterfaceTokenERKNS_8String16E;
- _ZN7android6Parcel19writeString16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZN7android6Parcel20closeFileDescriptorsEv;
- _ZN7android6Parcel22writeDupFileDescriptorEi;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZN7android6Parcel25writeParcelFileDescriptorEib;
- _ZN7android6Parcel25writeUniqueFileDescriptorERKNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android6Parcel26writeRawNullableParcelableEPKNS_10ParcelableE;
- _ZN7android6Parcel27replaceCallingWorkSourceUidEj;
- _ZN7android6Parcel28writeDupParcelFileDescriptorEi;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZN7android6Parcel35writeDupImmutableBlobFileDescriptorEi;
- _ZN7android6Parcel4Blob4initEiPvjb;
- _ZN7android6Parcel4Blob5clearEv;
- _ZN7android6Parcel4Blob7releaseEv;
- _ZN7android6Parcel4BlobC1Ev;
- _ZN7android6Parcel4BlobC2Ev;
- _ZN7android6Parcel4BlobD1Ev;
- _ZN7android6Parcel4BlobD2Ev;
- _ZN7android6Parcel5writeEPKvj;
- _ZN7android6Parcel5writeERKNS0_26FlattenableHelperInterfaceE;
- _ZN7android6Parcel7setDataEPKhj;
- _ZN7android6Parcel8freeDataEv;
- _ZN7android6Parcel8growDataEj;
- _ZN7android6Parcel8setErrorEi;
- _ZN7android6Parcel9initStateEv;
- _ZN7android6Parcel9writeBlobEjbPNS0_12WritableBlobE;
- _ZN7android6Parcel9writeBoolEb;
- _ZN7android6Parcel9writeByteEa;
- _ZN7android6Parcel9writeCharEDs;
- _ZN7android6ParcelC1Ev;
- _ZN7android6ParcelC2Ev;
- _ZN7android6ParcelD1Ev;
- _ZN7android6ParcelD2Ev;
- _ZN7android7BBinder10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinder10pingBinderEv;
- _ZN7android7BBinder11getDebugPidEv;
- _ZN7android7BBinder11isInheritRtEv;
- _ZN7android7BBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android7BBinder11localBinderEv;
- _ZN7android7BBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android7BBinder12detachObjectEPKv;
- _ZN7android7BBinder12getExtensionEv;
- _ZN7android7BBinder12setExtensionERKNS_2spINS_7IBinderEEE;
- _ZN7android7BBinder12setInheritRtEb;
- _ZN7android7BBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android7BBinder15isRequestingSidEv;
- _ZN7android7BBinder16setRequestingSidEb;
- _ZN7android7BBinder17getOrCreateExtrasEv;
- _ZN7android7BBinder21getMinSchedulerPolicyEv;
- _ZN7android7BBinder21setMinSchedulerPolicyEii;
- _ZN7android7BBinder23getMinSchedulerPriorityEv;
- _ZN7android7BBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinderC1Ev;
- _ZN7android7BBinderC2Ev;
- _ZN7android7BBinderD0Ev;
- _ZN7android7BBinderD1Ev;
- _ZN7android7BBinderD2Ev;
- _ZN7android7content2pm18PackageChangeEvent14readFromParcelEPKNS_6ParcelE;
- _ZN7android7content2pm21IPackageManagerNative10descriptorE;
- _ZN7android7content2pm21IPackageManagerNative11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm21IPackageManagerNative12default_implE;
- _ZN7android7content2pm21IPackageManagerNative14getDefaultImplEv;
- _ZN7android7content2pm21IPackageManagerNative14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm21IPackageManagerNativeC2Ev;
- _ZN7android7content2pm21IPackageManagerNativeD0Ev;
- _ZN7android7content2pm21IPackageManagerNativeD1Ev;
- _ZN7android7content2pm21IPackageManagerNativeD2Ev;
- _ZN7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm22BnPackageManagerNativeC2Ev;
- _ZN7android7content2pm22BpPackageManagerNative14getAllPackagesEPNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative15getNamesForUidsERKNSt3__16vectorIiNS3_9allocatorIiEEEEPNS4_INS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEENS5_ISE_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative16getLocationFlagsERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPi;
- _ZN7android7content2pm22BpPackageManagerNative16hasSystemFeatureERKNS_8String16EiPb;
- _ZN7android7content2pm22BpPackageManagerNative19isPackageDebuggableERKNS_8String16EPb;
- _ZN7android7content2pm22BpPackageManagerNative22getInstallerForPackageERKNS_8String16EPNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative24getVersionCodeForPackageERKNS_8String16EPx;
- _ZN7android7content2pm22BpPackageManagerNative27hasSha256SigningCertificateERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEERKNS3_6vectorIhNS7_IhEEEEPb;
- _ZN7android7content2pm22BpPackageManagerNative28getModuleMetadataPackageNameEPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29getTargetSdkVersionForPackageERKNS_8String16EPi;
- _ZN7android7content2pm22BpPackageManagerNative29isAudioPlaybackCaptureAllowedERKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEPNS4_IbNS8_IbEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29registerPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNative31unregisterPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver10descriptorE;
- _ZN7android7content2pm22IPackageChangeObserver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver12default_implE;
- _ZN7android7content2pm22IPackageChangeObserver14getDefaultImplEv;
- _ZN7android7content2pm22IPackageChangeObserver14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm22IPackageChangeObserverC2Ev;
- _ZN7android7content2pm22IPackageChangeObserverD0Ev;
- _ZN7android7content2pm22IPackageChangeObserverD1Ev;
- _ZN7android7content2pm22IPackageChangeObserverD2Ev;
- _ZN7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm23BnPackageChangeObserverC2Ev;
- _ZN7android7content2pm23BpPackageChangeObserver16onPackageChangedERKNS1_18PackageChangeEventE;
- _ZN7android7content2pm23BpPackageChangeObserverC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm23BpPackageChangeObserverC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7HexDumpC1EPKvjj;
- _ZN7android7HexDumpC2EPKvjj;
- _ZN7android7IBinder11getDebugPidEPi;
- _ZN7android7IBinder11localBinderEv;
- _ZN7android7IBinder12getExtensionEPNS_2spIS0_EE;
- _ZN7android7IBinder12remoteBinderEv;
- _ZN7android7IBinder12shellCommandERKNS_2spIS0_EEiiiRNS_6VectorINS_8String16EEERKNS1_INS_14IShellCallbackEEERKNS1_INS_15IResultReceiverEEE;
- _ZN7android7IBinder19queryLocalInterfaceERKNS_8String16E;
- _ZN7android7IBinderC2Ev;
- _ZN7android7IBinderD0Ev;
- _ZN7android7IBinderD1Ev;
- _ZN7android7IBinderD2Ev;
- _ZN7android7IMemory10descriptorE;
- _ZN7android7IMemory11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7IMemory12default_implE;
- _ZN7android7IMemory14getDefaultImplEv;
- _ZN7android7IMemory14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android7IMemoryC2Ev;
- _ZN7android7IMemoryD0Ev;
- _ZN7android7IMemoryD1Ev;
- _ZN7android7IMemoryD2Ev;
- _ZN7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BnMemoryC2Ev;
- _ZN7android8BnMemoryD0Ev;
- _ZN7android8BnMemoryD1Ev;
- _ZN7android8BnMemoryD2Ev;
- _ZN7android8BpBinder10onFirstRefEv;
- _ZN7android8BpBinder10pingBinderEv;
- _ZN7android8BpBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android8BpBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android8BpBinder12detachObjectEPKv;
- _ZN7android8BpBinder12remoteBinderEv;
- _ZN7android8BpBinder12sendObituaryEv;
- _ZN7android8BpBinder12sTrackingMapE;
- _ZN7android8BpBinder13getCountByUidERNS_6VectorIjEES3_;
- _ZN7android8BpBinder13ObjectManager4killEv;
- _ZN7android8BpBinder13ObjectManager6attachEPKvPvS4_PFvS3_S4_S4_E;
- _ZN7android8BpBinder13ObjectManager6detachEPKv;
- _ZN7android8BpBinder13ObjectManagerC1Ev;
- _ZN7android8BpBinder13ObjectManagerC2Ev;
- _ZN7android8BpBinder13ObjectManagerD1Ev;
- _ZN7android8BpBinder13ObjectManagerD2Ev;
- _ZN7android8BpBinder13sTrackingLockE;
- _ZN7android8BpBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android8BpBinder14reportOneDeathERKNS0_8ObituaryE;
- _ZN7android8BpBinder14sLimitCallbackE;
- _ZN7android8BpBinder15onLastStrongRefEPKv;
- _ZN7android8BpBinder15sNumTrackedUidsE;
- _ZN7android8BpBinder16enableCountByUidEv;
- _ZN7android8BpBinder16setLimitCallbackEPFviE;
- _ZN7android8BpBinder17disableCountByUidEv;
- _ZN7android8BpBinder18sCountByUidEnabledE;
- _ZN7android8BpBinder19getBinderProxyCountEj;
- _ZN7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZN7android8BpBinder20setCountByUidEnabledEb;
- _ZN7android8BpBinder26sBinderProxyThrottleCreateE;
- _ZN7android8BpBinder29sBinderProxyCountLowWatermarkE;
- _ZN7android8BpBinder29setBinderProxyCountWatermarksEii;
- _ZN7android8BpBinder30sBinderProxyCountHighWatermarkE;
- _ZN7android8BpBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android8BpBinder6createEi;
- _ZN7android8BpBinder6createERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BpBinderC1EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC1EONS0_9RpcHandleE;
- _ZN7android8BpBinderC1EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderC2EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC2EONS0_9RpcHandleE;
- _ZN7android8BpBinderC2EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderD0Ev;
- _ZN7android8BpBinderD1Ev;
- _ZN7android8BpBinderD2Ev;
- _ZN7android8BpMemoryC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryD0Ev;
- _ZN7android8BpMemoryD1Ev;
- _ZN7android8BpMemoryD2Ev;
- _ZN7android8internal9Stability11getCategoryEPNS_7IBinderE;
- _ZN7android8internal9Stability11levelStringENS1_5LevelE;
- _ZN7android8internal9Stability13getLocalLevelEv;
- _ZN7android8internal9Stability15isDeclaredLevelENS1_5LevelE;
- _ZN7android8internal9Stability17debugLogStabilityERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability19markCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability22tryMarkCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability24requiresVintfDeclarationERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability25forceDowngradeToStabilityERKNS_2spINS_7IBinderEEENS1_5LevelE;
- _ZN7android8internal9Stability30forceDowngradeToLocalStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToSystemStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToVendorStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability5checkENS1_8CategoryENS1_5LevelE;
- _ZN7android8internal9Stability7setReprEPNS_7IBinderEij;
- _ZN7android8internal9Stability8Category11debugStringEv;
- _ZN7android8internal9Stability8markVndkEPNS_7IBinderE;
- _ZN7android8internal9Stability9markVintfEPNS_7IBinderE;
- _ZN7android8RpcState11CommandDataC1Ej;
- _ZN7android8RpcState11CommandDataC2Ej;
- _ZN7android8RpcState12countBindersEv;
- _ZN7android8RpcState12getSessionIdERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPi;
- _ZN7android8RpcState12waitForReplyERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPNS_6ParcelE;
- _ZN7android8RpcState13getMaxThreadsERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPj;
- _ZN7android8RpcState13getRootObjectERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState13sendDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressE;
- _ZN7android8RpcState15onBinderLeavingERKNS_2spINS_10RpcSessionEEERKNS1_INS_7IBinderEEEPNS_10RpcAddressE;
- _ZN7android8RpcState15processTransactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState16onBinderEnteringERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8RpcState16processDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState20getAndExecuteCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState20processServerCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState23processTransactInternalERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEENS0_11CommandDataE;
- _ZN7android8RpcState4dumpEv;
- _ZN7android8RpcState6rpcRecERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPvj;
- _ZN7android8RpcState7rpcSendERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPKvj;
- _ZN7android8RpcState8transactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressEjRKNS_6ParcelERKNS_2spINS_10RpcSessionEEEPSA_j;
- _ZN7android8RpcState9terminateEv;
- _ZN7android8RpcStateC1Ev;
- _ZN7android8RpcStateC2Ev;
- _ZN7android8RpcStateD1Ev;
- _ZN7android8RpcStateD2Ev;
- _ZN7android9BpRefBase10onFirstRefEv;
- _ZN7android9BpRefBase15onLastStrongRefEPKv;
- _ZN7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZN7android9BpRefBaseC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseD0Ev;
- _ZN7android9BpRefBaseD1Ev;
- _ZN7android9BpRefBaseD2Ev;
- _ZN7android9HeapCache10binderDiedERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCache10dump_heapsEv;
- _ZN7android9HeapCache8get_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9find_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCacheC1Ev;
- _ZN7android9HeapCacheC2Ev;
- _ZN7android9HeapCacheD0Ev;
- _ZN7android9HeapCacheD1Ev;
- _ZN7android9HeapCacheD2Ev;
- _ZN7android9hexStringEPKvj;
- _ZN7android9RpcServer12listSessionsEv;
- _ZN7android9RpcServer13getMaxThreadsEv;
- _ZN7android9RpcServer13getRootObjectEv;
- _ZN7android9RpcServer13releaseServerEv;
- _ZN7android9RpcServer13setMaxThreadsEj;
- _ZN7android9RpcServer13setRootObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android9RpcServer15setupInetServerEjPj;
- _ZN7android9RpcServer16setupVsockServerEj;
- _ZN7android9RpcServer17setRootObjectWeakERKNS_2wpINS_7IBinderEEE;
- _ZN7android9RpcServer17setupSocketServerERKNS_16RpcSocketAddressE;
- _ZN7android9RpcServer19establishConnectionEONS_2spIS0_EENS_4base14unique_fd_implINS4_13DefaultCloserEEE;
- _ZN7android9RpcServer19setupExternalServerENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android9RpcServer20onSessionTerminatingERKNS_2spINS_10RpcSessionEEE;
- _ZN7android9RpcServer21setupUnixDomainServerEPKc;
- _ZN7android9RpcServer24numUninitializedSessionsEv;
- _ZN7android9RpcServer4joinEv;
- _ZN7android9RpcServer4makeEv;
- _ZN7android9RpcServer61iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProductionEv;
- _ZN7android9RpcServer9acceptOneEv;
- _ZN7android9RpcServer9hasServerEv;
- _ZN7android9RpcServerC1Ev;
- _ZN7android9RpcServerC2Ev;
- _ZN7android9RpcServerD0Ev;
- _ZN7android9RpcServerD1Ev;
- _ZN7android9RpcServerD2Ev;
- _ZN7androidlsERNS_10TextOutputERKNS_7HexDumpE;
- _ZN7androidlsERNS_10TextOutputERKNS_8TypeCodeE;
- _ZN7androidlsIA15_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA24_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA2_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA34_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA3_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA43_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA4_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA5_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA8_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA9_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIjEERNS_10TextOutputES2_RKT_;
- _ZN7androidlsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERNS_10TextOutputES9_RKT_;
- _ZN7androidlsIPcEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIPvEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIyEERNS_10TextOutputES2_RKT_;
- _ZNK7android10MemoryBase9getMemoryEPiPj;
- _ZNK7android10RpcAddress13writeToParcelEPNS_6ParcelE;
- _ZNK7android10RpcAddress15viewRawEmbeddedEv;
- _ZNK7android10RpcAddress6isZeroEv;
- _ZNK7android10RpcAddress8toStringEv;
- _ZNK7android10RpcAddressltERKS0_;
- _ZNK7android11IMemoryHeap22getInterfaceDescriptorEv;
- _ZNK7android12BpMemoryHeap12assertMappedEv;
- _ZNK7android12BpMemoryHeap18assertReallyMappedEv;
- _ZNK7android12BpMemoryHeap7getBaseEv;
- _ZNK7android12BpMemoryHeap7getSizeEv;
- _ZNK7android12BpMemoryHeap8getFlagsEv;
- _ZNK7android12BpMemoryHeap9getHeapIDEv;
- _ZNK7android12BpMemoryHeap9getOffsetEv;
- _ZNK7android12MemoryDealer4dumpEPKc;
- _ZNK7android12MemoryDealer4heapEv;
- _ZNK7android12MemoryDealer9allocatorEv;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_compareEPKvSA_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_destroyEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE12do_constructEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE15do_move_forwardEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE16do_move_backwardEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE7do_copyEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE8do_splatEPvPKvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_compareES3_S3_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_destroyEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE12do_constructEPvj;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE15do_move_forwardEPvS3_j;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE16do_move_backwardEPvS3_j;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE7do_copyEPvS3_j;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE8do_splatEPvS3_j;
- _ZNK7android14IPCThreadState13getCallingPidEv;
- _ZNK7android14IPCThreadState13getCallingSidEv;
- _ZNK7android14IPCThreadState13getCallingUidEv;
- _ZNK7android14IPCThreadState18getCallRestrictionEv;
- _ZNK7android14IPCThreadState19getStrictModePolicyEv;
- _ZNK7android14IPCThreadState22getServingStackPointerEv;
- _ZNK7android14IPCThreadState23getCallingWorkSourceUidEv;
- _ZNK7android14IPCThreadState25shouldPropagateWorkSourceEv;
- _ZNK7android14IPCThreadState29getLastTransactionBinderFlagsEv;
- _ZNK7android14IShellCallback22getInterfaceDescriptorEv;
- _ZNK7android14MemoryHeapBase7getBaseEv;
- _ZNK7android14MemoryHeapBase7getSizeEv;
- _ZNK7android14MemoryHeapBase8getFlagsEv;
- _ZNK7android14MemoryHeapBase9getDeviceEv;
- _ZNK7android14MemoryHeapBase9getHeapIDEv;
- _ZNK7android14MemoryHeapBase9getOffsetEv;
- _ZNK7android15IResultReceiver22getInterfaceDescriptorEv;
- _ZNK7android15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android18BufferedTextOutput9getBufferEv;
- _ZNK7android18ServiceManagerShim10getServiceERKNS_8String16E;
- _ZNK7android18ServiceManagerShim12checkServiceERKNS_8String16E;
- _ZNK7android22SimpleBestFitAllocator4dumpEPKc;
- _ZNK7android22SimpleBestFitAllocator4dumpERNS_7String8EPKc;
- _ZNK7android22SimpleBestFitAllocator4sizeEv;
- _ZNK7android22SimpleBestFitAllocator6dump_lEPKc;
- _ZNK7android22SimpleBestFitAllocator6dump_lERNS_7String8EPKc;
- _ZNK7android2os15IClientCallback22getInterfaceDescriptorEv;
- _ZNK7android2os15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android2os16IServiceCallback22getInterfaceDescriptorEv;
- _ZNK7android2os16ParcelableHolder13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os16ServiceDebugInfo13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle10getBooleanERKNS_8String16EPb;
- _ZNK7android2os17PersistableBundle10getIntKeysEv;
- _ZNK7android2os17PersistableBundle11getLongKeysEv;
- _ZNK7android2os17PersistableBundle12getIntVectorERKNS_8String16EPNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZNK7android2os17PersistableBundle13getDoubleKeysEv;
- _ZNK7android2os17PersistableBundle13getLongVectorERKNS_8String16EPNSt3__16vectorIxNS5_9allocatorIxEEEE;
- _ZNK7android2os17PersistableBundle13getStringKeysEv;
- _ZNK7android2os17PersistableBundle13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle14getBooleanKeysEv;
- _ZNK7android2os17PersistableBundle15getDoubleVectorERKNS_8String16EPNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZNK7android2os17PersistableBundle15getStringVectorERKNS_8String16EPNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZNK7android2os17PersistableBundle16getBooleanVectorERKNS_8String16EPNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZNK7android2os17PersistableBundle16getIntVectorKeysEv;
- _ZNK7android2os17PersistableBundle17getLongVectorKeysEv;
- _ZNK7android2os17PersistableBundle18writeToParcelInnerEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle19getDoubleVectorKeysEv;
- _ZNK7android2os17PersistableBundle19getStringVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getBooleanVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getPersistableBundleERKNS_8String16EPS1_;
- _ZNK7android2os17PersistableBundle24getPersistableBundleKeysEv;
- _ZNK7android2os17PersistableBundle4sizeEv;
- _ZNK7android2os17PersistableBundle5emptyEv;
- _ZNK7android2os17PersistableBundle6getIntERKNS_8String16EPi;
- _ZNK7android2os17PersistableBundle7getLongERKNS_8String16EPx;
- _ZNK7android2os17PersistableBundle9getDoubleERKNS_8String16EPd;
- _ZNK7android2os17PersistableBundle9getStringERKNS_8String16EPS2_;
- _ZNK7android2os20ParcelFileDescriptor13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status9toString8Ev;
- _ZNK7android6Parcel10errorCheckEv;
- _ZNK7android6Parcel10ipcObjectsEv;
- _ZNK7android6Parcel10readDoubleEPd;
- _ZNK7android6Parcel10readDoubleEv;
- _ZNK7android6Parcel10readObjectEb;
- _ZNK7android6Parcel10readUint32EPj;
- _ZNK7android6Parcel10readUint32Ev;
- _ZNK7android6Parcel10readUint64EPy;
- _ZNK7android6Parcel10readUint64Ev;
- _ZNK7android6Parcel10scanForFdsEv;
- _ZNK7android6Parcel11ipcDataSizeEv;
- _ZNK7android6Parcel11readCStringEv;
- _ZNK7android6Parcel11readInplaceEj;
- _ZNK7android6Parcel11readPointerEPj;
- _ZNK7android6Parcel11readPointerEv;
- _ZNK7android6Parcel11readString8EPNS_7String8E;
- _ZNK7android6Parcel11readString8Ev;
- _ZNK7android6Parcel12dataCapacityEv;
- _ZNK7android6Parcel12dataPositionEv;
- _ZNK7android6Parcel12objectsCountEv;
- _ZNK7android6Parcel12readString16EPNS_8String16E;
- _ZNK7android6Parcel12readString16EPNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZNK7android6Parcel12readString16EPNSt3__18optionalINS_8String16EEE;
- _ZNK7android6Parcel12readString16Ev;
- _ZNK7android6Parcel13markSensitiveEv;
- _ZNK7android6Parcel14checkInterfaceEPNS_7IBinderE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZNK7android6Parcel14readParcelableEPNS_10ParcelableE;
- _ZNK7android6Parcel15ipcObjectsCountEv;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__110unique_ptrINS1_6vectorIxNS1_9allocatorIxEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__16vectorIxNS1_9allocatorIxEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__18optionalINS1_6vectorIxNS1_9allocatorIxEEEEEE;
- _ZNK7android6Parcel15setDataPositionEj;
- _ZNK7android6Parcel15unflattenBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16enforceInterfaceEPKDsjPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16enforceInterfaceERKNS_8String16EPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZNK7android6Parcel16readNativeHandleEv;
- _ZNK7android6Parcel16readStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16readStrongBinderEv;
- _ZNK7android6Parcel16readStrongBinderINS_2os15IClientCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_2os16IServiceCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_7content2pm22IPackageChangeObserverEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__110unique_ptrINS1_6vectorIyNS1_9allocatorIyEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__16vectorIyNS1_9allocatorIyEEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__18optionalINS1_6vectorIyNS1_9allocatorIyEEEEEE;
- _ZNK7android6Parcel16validateReadDataEj;
- _ZNK7android6Parcel17getBlobAshmemSizeEv;
- _ZNK7android6Parcel17getOpenAshmemSizeEv;
- _ZNK7android6Parcel17readExceptionCodeEv;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZNK7android6Parcel18hasFileDescriptorsEv;
- _ZNK7android6Parcel18readFileDescriptorEv;
- _ZNK7android6Parcel18readString16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZNK7android6Parcel18readString8InplaceEPj;
- _ZNK7android6Parcel19readString16InplaceEPj;
- _ZNK7android6Parcel21finishUnflattenBinderERKNS_2spINS_7IBinderEEEPS3_;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZNK7android6Parcel24readCallingWorkSourceUidEv;
- _ZNK7android6Parcel24readNullableStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel24readParcelFileDescriptorEv;
- _ZNK7android6Parcel24readUniqueFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZNK7android6Parcel30readUniqueParcelFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel37updateWorkSourceRequestHeaderPositionEv;
- _ZNK7android6Parcel4dataEv;
- _ZNK7android6Parcel4readEPvj;
- _ZNK7android6Parcel4readERNS0_26FlattenableHelperInterfaceE;
- _ZNK7android6Parcel5printERNS_10TextOutputEj;
- _ZNK7android6Parcel7ipcDataEv;
- _ZNK7android6Parcel8allowFdsEv;
- _ZNK7android6Parcel8dataSizeEv;
- _ZNK7android6Parcel8isForRpcEv;
- _ZNK7android6Parcel8readBlobEjPNS0_12ReadableBlobE;
- _ZNK7android6Parcel8readBoolEPb;
- _ZNK7android6Parcel8readBoolEv;
- _ZNK7android6Parcel8readByteEPa;
- _ZNK7android6Parcel8readByteEv;
- _ZNK7android6Parcel8readCharEPDs;
- _ZNK7android6Parcel8readCharEv;
- _ZNK7android6Parcel9dataAvailEv;
- _ZNK7android6Parcel9readFloatEPf;
- _ZNK7android6Parcel9readFloatEv;
- _ZNK7android6Parcel9readInt32EPi;
- _ZNK7android6Parcel9readInt32Ev;
- _ZNK7android6Parcel9readInt64EPx;
- _ZNK7android6Parcel9readInt64Ev;
- _ZNK7android6VectorIiE10do_destroyEPvj;
- _ZNK7android6VectorIiE12do_constructEPvj;
- _ZNK7android6VectorIiE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIiE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIiE7do_copyEPvPKvj;
- _ZNK7android6VectorIiE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE10do_destroyEPvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE12do_constructEPvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE10do_destroyEPvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE12do_constructEPvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE10do_destroyEPvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE12do_constructEPvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE8do_splatEPvPKvj;
- _ZNK7android6VectorINS_8String16EE10do_destroyEPvj;
- _ZNK7android6VectorINS_8String16EE12do_constructEPvj;
- _ZNK7android6VectorINS_8String16EE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorINS_8String16EE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorINS_8String16EE7do_copyEPvPKvj;
- _ZNK7android6VectorINS_8String16EE8do_splatEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE10do_destroyEPvj;
- _ZNK7android6VectorIPNS_7BBinderEE12do_constructEPvj;
- _ZNK7android6VectorIPNS_7BBinderEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE7do_copyEPvPKvj;
- _ZNK7android6VectorIPNS_7BBinderEE8do_splatEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE10do_destroyEPvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE12do_constructEPvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE7do_copyEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE8do_splatEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE10do_destroyEPvj;
- _ZNK7android6VectorIPNS_7RefBaseEE12do_constructEPvj;
- _ZNK7android6VectorIPNS_7RefBaseEE15do_move_forwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE16do_move_backwardEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE7do_copyEPvPKvj;
- _ZNK7android6VectorIPNS_7RefBaseEE8do_splatEPvPKvj;
- _ZNK7android7BBinder10findObjectEPKv;
- _ZNK7android7BBinder13isBinderAliveEv;
- _ZNK7android7BBinder22getInterfaceDescriptorEv;
- _ZNK7android7content2pm18PackageChangeEvent13writeToParcelEPNS_6ParcelE;
- _ZNK7android7content2pm21IPackageManagerNative22getInterfaceDescriptorEv;
- _ZNK7android7content2pm22IPackageChangeObserver22getInterfaceDescriptorEv;
- _ZNK7android7IBinder13checkSubclassEPKv;
- _ZNK7android7IMemory11fastPointerERKNS_2spINS_7IBinderEEEi;
- _ZNK7android7IMemory15unsecurePointerEv;
- _ZNK7android7IMemory22getInterfaceDescriptorEv;
- _ZNK7android7IMemory4sizeEv;
- _ZNK7android7IMemory6offsetEv;
- _ZNK7android7IMemory7pointerEv;
- _ZNK7android8BpBinder10findObjectEPKv;
- _ZNK7android8BpBinder10rpcAddressEv;
- _ZNK7android8BpBinder10rpcSessionEv;
- _ZNK7android8BpBinder11isRpcBinderEv;
- _ZNK7android8BpBinder12binderHandleEv;
- _ZNK7android8BpBinder13isBinderAliveEv;
- _ZNK7android8BpBinder13ObjectManager4findEPKv;
- _ZNK7android8BpBinder18isDescriptorCachedEv;
- _ZNK7android8BpBinder22getInterfaceDescriptorEv;
- _ZNK7android8BpMemory9getMemoryEPiPj;
- _ZTCN7android10AllocationE0_NS_10IInterfaceE;
- _ZTCN7android10AllocationE0_NS_10MemoryBaseE;
- _ZTCN7android10AllocationE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10AllocationE0_NS_7IMemoryE;
- _ZTCN7android10AllocationE0_NS_8BnMemoryE;
- _ZTCN7android10AllocationE4_NS_7BBinderE;
- _ZTCN7android10AllocationE4_NS_7IBinderE;
- _ZTCN7android10MemoryBaseE0_NS_10IInterfaceE;
- _ZTCN7android10MemoryBaseE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10MemoryBaseE0_NS_7IMemoryE;
- _ZTCN7android10MemoryBaseE0_NS_8BnMemoryE;
- _ZTCN7android10MemoryBaseE4_NS_7BBinderE;
- _ZTCN7android10MemoryBaseE4_NS_7IBinderE;
- _ZTCN7android10PoolThreadE0_NS_6ThreadE;
- _ZTCN7android11IMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BnMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BnMemoryHeapE4_NS_7BBinderE;
- _ZTCN7android12BnMemoryHeapE4_NS_7IBinderE;
- _ZTCN7android12BpMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BpMemoryHeapE0_NS_11BpInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BpMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BpMemoryHeapE4_NS_9BpRefBaseE;
- _ZTCN7android14IShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE32_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE32_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android14MemoryHeapBaseE32_NS_11IMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE32_NS_12BnMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE36_NS_7BBinderE;
- _ZTCN7android14MemoryHeapBaseE36_NS_7IBinderE;
- _ZTCN7android15BnShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BnShellCallbackE0_NS_11BnInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BnShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BnShellCallbackE4_NS_7BBinderE;
- _ZTCN7android15BnShellCallbackE4_NS_7IBinderE;
- _ZTCN7android15BpShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BpShellCallbackE0_NS_11BpInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BpShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BpShellCallbackE4_NS_9BpRefBaseE;
- _ZTCN7android15IResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_11BnInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BnResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BnResultReceiverE4_NS_7BBinderE;
- _ZTCN7android16BnResultReceiverE4_NS_7IBinderE;
- _ZTCN7android16BpResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BpResultReceiverE0_NS_11BpInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BpResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BpResultReceiverE4_NS_9BpRefBaseE;
- _ZTCN7android18ServiceManagerShimE0_NS_10IInterfaceE;
- _ZTCN7android18ServiceManagerShimE0_NS_15IServiceManagerE;
- _ZTCN7android2os15IClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BnClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS_11BnInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BnClientCallbackE4_NS_7BBinderE;
- _ZTCN7android2os16BnClientCallbackE4_NS_7IBinderE;
- _ZTCN7android2os16BnServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BnServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnServiceManagerE0_NS_11BnInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BnServiceManagerE4_NS_7BBinderE;
- _ZTCN7android2os16BnServiceManagerE4_NS_7IBinderE;
- _ZTCN7android2os16BpClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BpClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpClientCallbackE0_NS_11BpInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BpClientCallbackE4_NS_9BpRefBaseE;
- _ZTCN7android2os16BpServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BpServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpServiceManagerE0_NS_11BpInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BpServiceManagerE4_NS_9BpRefBaseE;
- _ZTCN7android2os16IServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_11BnInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BnServiceCallbackE4_NS_7BBinderE;
- _ZTCN7android2os17BnServiceCallbackE4_NS_7IBinderE;
- _ZTCN7android2os17BpServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_11BpInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BpServiceCallbackE4_NS_9BpRefBaseE;
- _ZTCN7android7BBinderE0_NS_7IBinderE;
- _ZTCN7android7content2pm21IPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_11BnInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE4_NS_7BBinderE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE4_NS_7IBinderE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_11BpInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE4_NS_9BpRefBaseE;
- _ZTCN7android7content2pm22IPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_11BnInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE4_NS_7BBinderE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE4_NS_7IBinderE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_11BpInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE4_NS_9BpRefBaseE;
- _ZTCN7android7IMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BnMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BnMemoryE4_NS_7BBinderE;
- _ZTCN7android8BnMemoryE4_NS_7IBinderE;
- _ZTCN7android8BpBinderE0_NS_7IBinderE;
- _ZTCN7android8BpMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BpMemoryE0_NS_11BpInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BpMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BpMemoryE4_NS_9BpRefBaseE;
- _ZTCN7android9HeapCacheE0_NS_7IBinder14DeathRecipientE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_13basic_istreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_14basic_iostreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE8_NS_13basic_ostreamIcS2_EE;
- _ZThn4_N7android10AllocationD0Ev;
- _ZThn4_N7android10AllocationD1Ev;
- _ZThn4_N7android10MemoryBaseD0Ev;
- _ZThn4_N7android10MemoryBaseD1Ev;
- _ZThn4_N7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android12BnMemoryHeapD0Ev;
- _ZThn4_N7android12BnMemoryHeapD1Ev;
- _ZThn4_N7android12BpMemoryHeapD0Ev;
- _ZThn4_N7android12BpMemoryHeapD1Ev;
- _ZThn4_N7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn4_N7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn4_N7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn4_N7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn4_N7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn4_N7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn4_N7android8BnMemoryD0Ev;
- _ZThn4_N7android8BnMemoryD1Ev;
- _ZThn4_N7android8BpMemoryD0Ev;
- _ZThn4_N7android8BpMemoryD1Ev;
- _ZTTN7android10AllocationE;
- _ZTTN7android10IInterfaceE;
- _ZTTN7android10MemoryBaseE;
- _ZTTN7android10PoolThreadE;
- _ZTTN7android10RpcSessionE;
- _ZTTN7android11IMemoryHeapE;
- _ZTTN7android12BnMemoryHeapE;
- _ZTTN7android12BpMemoryHeapE;
- _ZTTN7android12ProcessStateE;
- _ZTTN7android14IShellCallbackE;
- _ZTTN7android14MemoryHeapBaseE;
- _ZTTN7android15BnShellCallbackE;
- _ZTTN7android15BpShellCallbackE;
- _ZTTN7android15IResultReceiverE;
- _ZTTN7android15IServiceManagerE;
- _ZTTN7android16BnResultReceiverE;
- _ZTTN7android16BpResultReceiverE;
- _ZTTN7android18ServiceManagerShimE;
- _ZTTN7android2os15IClientCallbackE;
- _ZTTN7android2os15IServiceManagerE;
- _ZTTN7android2os16BnClientCallbackE;
- _ZTTN7android2os16BnServiceManagerE;
- _ZTTN7android2os16BpClientCallbackE;
- _ZTTN7android2os16BpServiceManagerE;
- _ZTTN7android2os16IServiceCallbackE;
- _ZTTN7android2os17BnServiceCallbackE;
- _ZTTN7android2os17BpServiceCallbackE;
- _ZTTN7android7BBinderE;
- _ZTTN7android7content2pm21IPackageManagerNativeE;
- _ZTTN7android7content2pm22BnPackageManagerNativeE;
- _ZTTN7android7content2pm22BpPackageManagerNativeE;
- _ZTTN7android7content2pm22IPackageChangeObserverE;
- _ZTTN7android7content2pm23BnPackageChangeObserverE;
- _ZTTN7android7content2pm23BpPackageChangeObserverE;
- _ZTTN7android7IBinderE;
- _ZTTN7android7IMemoryE;
- _ZTTN7android8BnMemoryE;
- _ZTTN7android8BpBinderE;
- _ZTTN7android8BpMemoryE;
- _ZTTN7android9BpRefBaseE;
- _ZTTN7android9HeapCacheE;
- _ZTTN7android9RpcServerE;
- _ZTTNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE;
- _ZTv0_n12_N7android10AllocationD0Ev;
- _ZTv0_n12_N7android10AllocationD1Ev;
- _ZTv0_n12_N7android10IInterfaceD0Ev;
- _ZTv0_n12_N7android10IInterfaceD1Ev;
- _ZTv0_n12_N7android10MemoryBaseD0Ev;
- _ZTv0_n12_N7android10MemoryBaseD1Ev;
- _ZTv0_n12_N7android10RpcSessionD0Ev;
- _ZTv0_n12_N7android10RpcSessionD1Ev;
- _ZTv0_n12_N7android11IMemoryHeapD0Ev;
- _ZTv0_n12_N7android11IMemoryHeapD1Ev;
- _ZTv0_n12_N7android12BnMemoryHeapD0Ev;
- _ZTv0_n12_N7android12BnMemoryHeapD1Ev;
- _ZTv0_n12_N7android12BpMemoryHeapD0Ev;
- _ZTv0_n12_N7android12BpMemoryHeapD1Ev;
- _ZTv0_n12_N7android12ProcessStateD0Ev;
- _ZTv0_n12_N7android12ProcessStateD1Ev;
- _ZTv0_n12_N7android14IShellCallbackD0Ev;
- _ZTv0_n12_N7android14IShellCallbackD1Ev;
- _ZTv0_n12_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n12_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n12_N7android15IResultReceiverD0Ev;
- _ZTv0_n12_N7android15IResultReceiverD1Ev;
- _ZTv0_n12_N7android15IServiceManagerD0Ev;
- _ZTv0_n12_N7android15IServiceManagerD1Ev;
- _ZTv0_n12_N7android2os15IClientCallbackD0Ev;
- _ZTv0_n12_N7android2os15IClientCallbackD1Ev;
- _ZTv0_n12_N7android2os15IServiceManagerD0Ev;
- _ZTv0_n12_N7android2os15IServiceManagerD1Ev;
- _ZTv0_n12_N7android2os16IServiceCallbackD0Ev;
- _ZTv0_n12_N7android2os16IServiceCallbackD1Ev;
- _ZTv0_n12_N7android7BBinderD0Ev;
- _ZTv0_n12_N7android7BBinderD1Ev;
- _ZTv0_n12_N7android7content2pm21IPackageManagerNativeD0Ev;
- _ZTv0_n12_N7android7content2pm21IPackageManagerNativeD1Ev;
- _ZTv0_n12_N7android7content2pm22IPackageChangeObserverD0Ev;
- _ZTv0_n12_N7android7content2pm22IPackageChangeObserverD1Ev;
- _ZTv0_n12_N7android7IBinderD0Ev;
- _ZTv0_n12_N7android7IBinderD1Ev;
- _ZTv0_n12_N7android7IMemoryD0Ev;
- _ZTv0_n12_N7android7IMemoryD1Ev;
- _ZTv0_n12_N7android8BnMemoryD0Ev;
- _ZTv0_n12_N7android8BnMemoryD1Ev;
- _ZTv0_n12_N7android8BpBinderD0Ev;
- _ZTv0_n12_N7android8BpBinderD1Ev;
- _ZTv0_n12_N7android8BpMemoryD0Ev;
- _ZTv0_n12_N7android8BpMemoryD1Ev;
- _ZTv0_n12_N7android9BpRefBaseD0Ev;
- _ZTv0_n12_N7android9BpRefBaseD1Ev;
- _ZTv0_n12_N7android9HeapCacheD0Ev;
- _ZTv0_n12_N7android9HeapCacheD1Ev;
- _ZTv0_n12_N7android9RpcServerD0Ev;
- _ZTv0_n12_N7android9RpcServerD1Ev;
- _ZTv0_n16_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n16_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n16_N7android8BpBinder10onFirstRefEv;
- _ZTv0_n16_N7android9BpRefBase10onFirstRefEv;
- _ZTv0_n20_N7android8BpBinder15onLastStrongRefEPKv;
- _ZTv0_n20_N7android9BpRefBase15onLastStrongRefEPKv;
- _ZTv0_n24_N7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZTv0_n24_N7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZTv0_n28_NK7android14MemoryHeapBase9getHeapIDEv;
- _ZTv0_n32_NK7android14MemoryHeapBase7getBaseEv;
- _ZTv0_n36_NK7android14MemoryHeapBase7getSizeEv;
- _ZTv0_n40_NK7android14MemoryHeapBase8getFlagsEv;
- _ZTv0_n44_NK7android14MemoryHeapBase9getOffsetEv;
- _ZTvn4_n16_N7android14MemoryHeapBaseD0Ev;
- _ZTvn4_n16_N7android14MemoryHeapBaseD1Ev;
- _ZTVN7android10AllocationE;
- _ZTVN7android10IInterfaceE;
- _ZTVN7android10MemoryBaseE;
- _ZTVN7android10PoolThreadE;
- _ZTVN7android10RpcSession13RpcConnectionE;
- _ZTVN7android10RpcSessionE;
- _ZTVN7android10TextOutputE;
- _ZTVN7android11IMemoryHeapE;
- _ZTVN7android12BnMemoryHeapE;
- _ZTVN7android12BpMemoryHeapE;
- _ZTVN7android12FdTextOutputE;
- _ZTVN7android12MemoryDealerE;
- _ZTVN7android12ProcessStateE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEEE;
- _ZTVN7android13LogTextOutputE;
- _ZTVN7android14IShellCallbackE;
- _ZTVN7android14MemoryHeapBaseE;
- _ZTVN7android15BnShellCallbackE;
- _ZTVN7android15BpShellCallbackE;
- _ZTVN7android15IResultReceiverE;
- _ZTVN7android15IServiceManagerE;
- _ZTVN7android16BnResultReceiverE;
- _ZTVN7android16BpResultReceiverE;
- _ZTVN7android17InetSocketAddressE;
- _ZTVN7android17UnixSocketAddressE;
- _ZTVN7android18BufferedTextOutput11BufferStateE;
- _ZTVN7android18BufferedTextOutputE;
- _ZTVN7android18ServiceManagerShimE;
- _ZTVN7android18VsockSocketAddressE;
- _ZTVN7android2os15IClientCallbackE;
- _ZTVN7android2os15IServiceManagerE;
- _ZTVN7android2os16BnClientCallbackE;
- _ZTVN7android2os16BnServiceManagerE;
- _ZTVN7android2os16BpClientCallbackE;
- _ZTVN7android2os16BpServiceManagerE;
- _ZTVN7android2os16IServiceCallbackE;
- _ZTVN7android2os16ParcelableHolderE;
- _ZTVN7android2os16ServiceDebugInfoE;
- _ZTVN7android2os17BnServiceCallbackE;
- _ZTVN7android2os17BpServiceCallbackE;
- _ZTVN7android2os17PersistableBundleE;
- _ZTVN7android2os20ParcelFileDescriptorE;
- _ZTVN7android6VectorIiEE;
- _ZTVN7android6VectorINS_12ProcessState12handle_entryEEE;
- _ZTVN7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEEE;
- _ZTVN7android6VectorINS_8BpBinder8ObituaryEEE;
- _ZTVN7android6VectorINS_8String16EEE;
- _ZTVN7android6VectorIPNS_7BBinderEEE;
- _ZTVN7android6VectorIPNS_7RefBase12weakref_typeEEE;
- _ZTVN7android6VectorIPNS_7RefBaseEEE;
- _ZTVN7android7BBinderE;
- _ZTVN7android7content2pm18PackageChangeEventE;
- _ZTVN7android7content2pm21IPackageManagerNativeE;
- _ZTVN7android7content2pm22BnPackageManagerNativeE;
- _ZTVN7android7content2pm22BpPackageManagerNativeE;
- _ZTVN7android7content2pm22IPackageChangeObserverE;
- _ZTVN7android7content2pm23BnPackageChangeObserverE;
- _ZTVN7android7content2pm23BpPackageChangeObserverE;
- _ZTVN7android7IBinderE;
- _ZTVN7android7IMemoryE;
- _ZTVN7android8BnMemoryE;
- _ZTVN7android8BpBinderE;
- _ZTVN7android8BpMemoryE;
- _ZTVN7android9BpRefBaseE;
- _ZTVN7android9HeapCacheE;
- _ZTVN7android9RpcServerE;
- local:
- *;
-};
diff --git a/libs/binder/libbinder.arm64.map b/libs/binder/libbinder.arm64.map
deleted file mode 100644
index 1d3da4c..0000000
--- a/libs/binder/libbinder.arm64.map
+++ /dev/null
@@ -1,1396 +0,0 @@
-# b/190148312: Populate with correct list of ABI symbols
-LIBBINDER {
- global:
- getBinderKernelReferences;
- kDefaultDriver;
- _ZN7android10AllocationC1ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEElm;
- _ZN7android10AllocationC2ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEElm;
- _ZN7android10AllocationD0Ev;
- _ZN7android10AllocationD1Ev;
- _ZN7android10AllocationD2Ev;
- _ZN7android10IInterface8asBinderEPKS0_;
- _ZN7android10IInterface8asBinderERKNS_2spIS0_EE;
- _ZN7android10IInterfaceC2Ev;
- _ZN7android10IInterfaceD0Ev;
- _ZN7android10IInterfaceD1Ev;
- _ZN7android10IInterfaceD2Ev;
- _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElm;
- _ZN7android10MemoryBaseC2ERKNS_2spINS_11IMemoryHeapEEElm;
- _ZN7android10MemoryBaseD0Ev;
- _ZN7android10MemoryBaseD1Ev;
- _ZN7android10MemoryBaseD2Ev;
- _ZN7android10RpcAddress14readFromParcelERKNS_6ParcelE;
- _ZN7android10RpcAddress15fromRawEmbeddedEPKNS_14RpcWireAddressE;
- _ZN7android10RpcAddress4zeroEv;
- _ZN7android10RpcAddress6uniqueEv;
- _ZN7android10RpcAddressC1Ev;
- _ZN7android10RpcAddressC2Ev;
- _ZN7android10RpcAddressD1Ev;
- _ZN7android10RpcAddressD2Ev;
- _ZN7android10RpcSession12setForServerERKNS_2wpINS_9RpcServerEEEi;
- _ZN7android10RpcSession13getRootObjectEv;
- _ZN7android10RpcSession13sendDecStrongERKNS_10RpcAddressE;
- _ZN7android10RpcSession15setupInetClientEPKcj;
- _ZN7android10RpcSession15terminateLockedEv;
- _ZN7android10RpcSession16setupVsockClientEjj;
- _ZN7android10RpcSession17setupSocketClientERKNS_16RpcSocketAddressE;
- _ZN7android10RpcSession19addClientConnectionENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession19ExclusiveConnection14findConnectionEiPNS_2spINS0_13RpcConnectionEEES5_RNSt3__16vectorIS4_NS6_9allocatorIS4_EEEEm;
- _ZN7android10RpcSession19ExclusiveConnectionC1ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionC2ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionD1Ev;
- _ZN7android10RpcSession19ExclusiveConnectionD2Ev;
- _ZN7android10RpcSession19getRemoteMaxThreadsEPm;
- _ZN7android10RpcSession20setupOneSocketClientERKNS_16RpcSocketAddressEi;
- _ZN7android10RpcSession21setupUnixDomainClientEPKc;
- _ZN7android10RpcSession22addNullDebuggingClientEv;
- _ZN7android10RpcSession22removeServerConnectionERKNS_2spINS0_13RpcConnectionEEE;
- _ZN7android10RpcSession24assignServerToThisThreadENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4joinENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4makeEv;
- _ZN7android10RpcSession6readIdEv;
- _ZN7android10RpcSession6serverEv;
- _ZN7android10RpcSession7preJoinENSt3__16threadE;
- _ZN7android10RpcSession8transactERKNS_10RpcAddressEjRKNS_6ParcelEPS4_j;
- _ZN7android10RpcSessionC1Ev;
- _ZN7android10RpcSessionC2Ev;
- _ZN7android10RpcSessionD0Ev;
- _ZN7android10RpcSessionD1Ev;
- _ZN7android10RpcSessionD2Ev;
- _ZN7android10TextOutputC2Ev;
- _ZN7android10TextOutputD0Ev;
- _ZN7android10TextOutputD1Ev;
- _ZN7android10TextOutputD2Ev;
- _ZN7android10zeroMemoryEPhm;
- _ZN7android11BnInterfaceINS_11IMemoryHeapEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_14IShellCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_15IResultReceiverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_21IPermissionControllerEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IClientCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IServiceManagerEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os16IServiceCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm21IPackageManagerNativeEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm22IPackageChangeObserverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7IMemoryEE10onAsBinderEv;
- _ZN7android11IMemoryHeap10descriptorE;
- _ZN7android11IMemoryHeap11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android11IMemoryHeap12default_implE;
- _ZN7android11IMemoryHeap14getDefaultImplEv;
- _ZN7android11IMemoryHeap14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android11IMemoryHeapC2Ev;
- _ZN7android11IMemoryHeapD0Ev;
- _ZN7android11IMemoryHeapD1Ev;
- _ZN7android11IMemoryHeapD2Ev;
- _ZN7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android12BnMemoryHeapC2Ev;
- _ZN7android12BnMemoryHeapD0Ev;
- _ZN7android12BnMemoryHeapD1Ev;
- _ZN7android12BnMemoryHeapD2Ev;
- _ZN7android12BpMemoryHeapC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapD0Ev;
- _ZN7android12BpMemoryHeapD1Ev;
- _ZN7android12BpMemoryHeapD2Ev;
- _ZN7android12gTextBuffersE;
- _ZN7android12MemoryDealer10deallocateEm;
- _ZN7android12MemoryDealer22getAllocationAlignmentEv;
- _ZN7android12MemoryDealer8allocateEm;
- _ZN7android12MemoryDealerC1EmPKcj;
- _ZN7android12MemoryDealerC2EmPKcj;
- _ZN7android12MemoryDealerD0Ev;
- _ZN7android12MemoryDealerD1Ev;
- _ZN7android12MemoryDealerD2Ev;
- _ZN7android12printHexDataEiPKvmmimbPFvPvPKcES2_;
- _ZN7android12ProcessState10selfOrNullEv;
- _ZN7android12ProcessState13expungeHandleEiPNS_7IBinderE;
- _ZN7android12ProcessState13getDriverNameEv;
- _ZN7android12ProcessState14initWithDriverEPKc;
- _ZN7android12ProcessState15startThreadPoolEv;
- _ZN7android12ProcessState16getContextObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android12ProcessState17spawnPooledThreadEb;
- _ZN7android12ProcessState18giveThreadPoolNameEv;
- _ZN7android12ProcessState18lookupHandleLockedEi;
- _ZN7android12ProcessState18setCallRestrictionENS0_15CallRestrictionE;
- _ZN7android12ProcessState19getKernelReferencesEmPm;
- _ZN7android12ProcessState20becomeContextManagerEv;
- _ZN7android12ProcessState20makeBinderThreadNameEv;
- _ZN7android12ProcessState23getStrongProxyForHandleEi;
- _ZN7android12ProcessState24getStrongRefCountForNodeERKNS_2spINS_8BpBinderEEE;
- _ZN7android12ProcessState25enableOnewaySpamDetectionEb;
- _ZN7android12ProcessState27setThreadPoolMaxThreadCountEm;
- _ZN7android12ProcessState4initEPKcb;
- _ZN7android12ProcessState4selfEv;
- _ZN7android12ProcessStateC1EPKc;
- _ZN7android12ProcessStateC2EPKc;
- _ZN7android12ProcessStateD0Ev;
- _ZN7android12ProcessStateD1Ev;
- _ZN7android12ProcessStateD2Ev;
- _ZN7android13printTypeCodeEjPFvPvPKcES0_;
- _ZN7android14IPCThreadState10freeBufferEPNS_6ParcelEPKhmPKym;
- _ZN7android14IPCThreadState10selfOrNullEv;
- _ZN7android14IPCThreadState11clearCallerEv;
- _ZN7android14IPCThreadState11stopProcessEb;
- _ZN7android14IPCThreadState12setupPollingEPi;
- _ZN7android14IPCThreadState13decWeakHandleEi;
- _ZN7android14IPCThreadState13expungeHandleEiPNS_7IBinderE;
- _ZN7android14IPCThreadState13flushCommandsEv;
- _ZN7android14IPCThreadState13flushIfNeededEv;
- _ZN7android14IPCThreadState13incWeakHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState14clearLastErrorEv;
- _ZN7android14IPCThreadState14executeCommandEi;
- _ZN7android14IPCThreadState14joinThreadPoolEb;
- _ZN7android14IPCThreadState14talkWithDriverEb;
- _ZN7android14IPCThreadState15decStrongHandleEi;
- _ZN7android14IPCThreadState15incStrongHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi;
- _ZN7android14IPCThreadState16threadDestructorEPv;
- _ZN7android14IPCThreadState18setCallRestrictionENS_12ProcessState15CallRestrictionE;
- _ZN7android14IPCThreadState19setStrictModePolicyEi;
- _ZN7android14IPCThreadState19setTheContextObjectERKNS_2spINS_7BBinderEEE;
- _ZN7android14IPCThreadState20clearCallingIdentityEv;
- _ZN7android14IPCThreadState20getAndExecuteCommandEv;
- _ZN7android14IPCThreadState20getProcessFreezeInfoEiPbS1_;
- _ZN7android14IPCThreadState20getProcessFreezeInfoEiPjS1_;
- _ZN7android14IPCThreadState20handlePolledCommandsEv;
- _ZN7android14IPCThreadState20processPendingDerefsEv;
- _ZN7android14IPCThreadState20writeTransactionDataEijijRKNS_6ParcelEPi;
- _ZN7android14IPCThreadState22attemptIncStrongHandleEi;
- _ZN7android14IPCThreadState22clearCallingWorkSourceEv;
- _ZN7android14IPCThreadState22clearDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState22processPostWriteDerefsEv;
- _ZN7android14IPCThreadState22restoreCallingIdentityEl;
- _ZN7android14IPCThreadState23setCallingWorkSourceUidEj;
- _ZN7android14IPCThreadState24clearPropagateWorkSourceEv;
- _ZN7android14IPCThreadState24requestDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState24restoreCallingWorkSourceEl;
- _ZN7android14IPCThreadState25blockUntilThreadAvailableEv;
- _ZN7android14IPCThreadState27disableBackgroundSchedulingEb;
- _ZN7android14IPCThreadState28backgroundSchedulingDisabledEv;
- _ZN7android14IPCThreadState29setLastTransactionBinderFlagsEi;
- _ZN7android14IPCThreadState41setCallingWorkSourceUidWithoutPropagationEj;
- _ZN7android14IPCThreadState4selfEv;
- _ZN7android14IPCThreadState6freezeEibj;
- _ZN7android14IPCThreadState7processEv;
- _ZN7android14IPCThreadState8shutdownEv;
- _ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j;
- _ZN7android14IPCThreadState9sendReplyERKNS_6ParcelEj;
- _ZN7android14IPCThreadStateC1Ev;
- _ZN7android14IPCThreadStateC2Ev;
- _ZN7android14IPCThreadStateD1Ev;
- _ZN7android14IPCThreadStateD2Ev;
- _ZN7android14IShellCallback10descriptorE;
- _ZN7android14IShellCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android14IShellCallback12default_implE;
- _ZN7android14IShellCallback14getDefaultImplEv;
- _ZN7android14IShellCallback14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android14IShellCallbackC2Ev;
- _ZN7android14IShellCallbackD0Ev;
- _ZN7android14IShellCallbackD1Ev;
- _ZN7android14IShellCallbackD2Ev;
- _ZN7android14MemoryHeapBase4initEiPvmiPKc;
- _ZN7android14MemoryHeapBase5mapfdEibml;
- _ZN7android14MemoryHeapBase7disposeEv;
- _ZN7android14MemoryHeapBaseC1Eimjl;
- _ZN7android14MemoryHeapBaseC1EmjPKc;
- _ZN7android14MemoryHeapBaseC1EPKcmj;
- _ZN7android14MemoryHeapBaseC1Ev;
- _ZN7android14MemoryHeapBaseC2Eimjl;
- _ZN7android14MemoryHeapBaseC2EmjPKc;
- _ZN7android14MemoryHeapBaseC2EPKcmj;
- _ZN7android14MemoryHeapBaseC2Ev;
- _ZN7android14MemoryHeapBaseD0Ev;
- _ZN7android14MemoryHeapBaseD1Ev;
- _ZN7android14MemoryHeapBaseD2Ev;
- _ZN7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android15checkPermissionERKNS_8String16Eij;
- _ZN7android15IResultReceiver10descriptorE;
- _ZN7android15IResultReceiver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android15IResultReceiver12default_implE;
- _ZN7android15IResultReceiver14getDefaultImplEv;
- _ZN7android15IResultReceiver14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android15IResultReceiverC2Ev;
- _ZN7android15IResultReceiverD0Ev;
- _ZN7android15IResultReceiverD1Ev;
- _ZN7android15IResultReceiverD2Ev;
- _ZN7android15IServiceManagerC2Ev;
- _ZN7android15IServiceManagerD0Ev;
- _ZN7android15IServiceManagerD1Ev;
- _ZN7android15IServiceManagerD2Ev;
- _ZN7android15PermissionCache10purgeCacheEv;
- _ZN7android15PermissionCache15checkPermissionERKNS_8String16Eij;
- _ZN7android15PermissionCache22checkCallingPermissionERKNS_8String16E;
- _ZN7android15PermissionCache22checkCallingPermissionERKNS_8String16EPiS4_;
- _ZN7android15PermissionCache5cacheERKNS_8String16Ejb;
- _ZN7android15PermissionCache5purgeEv;
- _ZN7android15PermissionCacheC1Ev;
- _ZN7android15PermissionCacheC2Ev;
- _ZN7android15stringForIndentEi;
- _ZN7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android18BufferedTextOutput10moveIndentEi;
- _ZN7android18BufferedTextOutput10pushBundleEv;
- _ZN7android18BufferedTextOutput5printEPKcm;
- _ZN7android18BufferedTextOutput9popBundleEv;
- _ZN7android18BufferedTextOutputC2Ej;
- _ZN7android18BufferedTextOutputD0Ev;
- _ZN7android18BufferedTextOutputD1Ev;
- _ZN7android18BufferedTextOutputD2Ev;
- _ZN7android18ServiceManagerShim10addServiceERKNS_8String16ERKNS_2spINS_7IBinderEEEbi;
- _ZN7android18ServiceManagerShim10isDeclaredERKNS_8String16E;
- _ZN7android18ServiceManagerShim12listServicesEi;
- _ZN7android18ServiceManagerShim14waitForServiceERKNS_8String16E;
- _ZN7android18ServiceManagerShim16updatableViaApexERKNS_8String16E;
- _ZN7android18ServiceManagerShim20getDeclaredInstancesERKNS_8String16E;
- _ZN7android18ServiceManagerShimC1ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18ServiceManagerShimC2ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18the_context_objectE;
- _ZN7android20PermissionController10getServiceEv;
- _ZN7android20PermissionController13getPackageUidERKNS_8String16Ei;
- _ZN7android20PermissionController15checkPermissionERKNS_8String16Eii;
- _ZN7android20PermissionController17getPackagesForUidEjRNS_6VectorINS_8String16EEE;
- _ZN7android20PermissionController19isRuntimePermissionERKNS_8String16E;
- _ZN7android20PermissionController6noteOpERKNS_8String16EiS3_;
- _ZN7android20PermissionControllerC1Ev;
- _ZN7android20PermissionControllerC2Ev;
- _ZN7android21defaultServiceManagerEv;
- _ZN7android21IPermissionController10descriptorE;
- _ZN7android21IPermissionController11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android21IPermissionController12default_implE;
- _ZN7android21IPermissionController14getDefaultImplEv;
- _ZN7android21IPermissionController14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android21IPermissionControllerC2Ev;
- _ZN7android21IPermissionControllerD0Ev;
- _ZN7android21IPermissionControllerD1Ev;
- _ZN7android21IPermissionControllerD2Ev;
- _ZN7android22BnPermissionController10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android22checkCallingPermissionERKNS_8String16E;
- _ZN7android22checkCallingPermissionERKNS_8String16EPiS3_;
- _ZN7android22SimpleBestFitAllocator10deallocateEm;
- _ZN7android22SimpleBestFitAllocator12kMemoryAlignE;
- _ZN7android22SimpleBestFitAllocator5allocEmj;
- _ZN7android22SimpleBestFitAllocator7deallocEm;
- _ZN7android22SimpleBestFitAllocator8allocateEmj;
- _ZN7android22SimpleBestFitAllocatorC1Em;
- _ZN7android22SimpleBestFitAllocatorC2Em;
- _ZN7android22SimpleBestFitAllocatorD1Ev;
- _ZN7android22SimpleBestFitAllocatorD2Ev;
- _ZN7android24setDefaultServiceManagerERKNS_2spINS_15IServiceManagerEEE;
- _ZN7android2os15IClientCallback10descriptorE;
- _ZN7android2os15IClientCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IClientCallback12default_implE;
- _ZN7android2os15IClientCallback14getDefaultImplEv;
- _ZN7android2os15IClientCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IClientCallbackC2Ev;
- _ZN7android2os15IClientCallbackD0Ev;
- _ZN7android2os15IClientCallbackD1Ev;
- _ZN7android2os15IClientCallbackD2Ev;
- _ZN7android2os15IServiceManager10descriptorE;
- _ZN7android2os15IServiceManager11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IServiceManager12default_implE;
- _ZN7android2os15IServiceManager14getDefaultImplEv;
- _ZN7android2os15IServiceManager14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IServiceManagerC2Ev;
- _ZN7android2os15IServiceManagerD0Ev;
- _ZN7android2os15IServiceManagerD1Ev;
- _ZN7android2os15IServiceManagerD2Ev;
- _ZN7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnClientCallbackC2Ev;
- _ZN7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnServiceManagerC2Ev;
- _ZN7android2os16BpClientCallback9onClientsERKNS_2spINS_7IBinderEEEb;
- _ZN7android2os16BpClientCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpClientCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10addServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEEbi;
- _ZN7android2os16BpServiceManager10getServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10isDeclaredERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPb;
- _ZN7android2os16BpServiceManager12checkServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager12listServicesEiPNSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEE;
- _ZN7android2os16BpServiceManager16updatableViaApexERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_8optionalIS8_EE;
- _ZN7android2os16BpServiceManager19getServiceDebugInfoEPNSt3__16vectorINS0_16ServiceDebugInfoENS2_9allocatorIS4_EEEE;
- _ZN7android2os16BpServiceManager20getDeclaredInstancesERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_6vectorIS8_NS6_IS8_EEEE;
- _ZN7android2os16BpServiceManager20tryUnregisterServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager22registerClientCallbackERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEERKNSB_INS0_15IClientCallbackEEE;
- _ZN7android2os16BpServiceManager24registerForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManager26unregisterForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManagerC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManagerC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback10descriptorE;
- _ZN7android2os16IServiceCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback12default_implE;
- _ZN7android2os16IServiceCallback14getDefaultImplEv;
- _ZN7android2os16IServiceCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os16IServiceCallbackC2Ev;
- _ZN7android2os16IServiceCallbackD0Ev;
- _ZN7android2os16IServiceCallbackD1Ev;
- _ZN7android2os16IServiceCallbackD2Ev;
- _ZN7android2os16ParcelableHolder14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os16ServiceDebugInfo14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os17BnServiceCallbackC2Ev;
- _ZN7android2os17BpServiceCallback14onRegistrationERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17PersistableBundle10putBooleanERKNS_8String16Eb;
- _ZN7android2os17PersistableBundle12putIntVectorERKNS_8String16ERKNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZN7android2os17PersistableBundle13putLongVectorERKNS_8String16ERKNSt3__16vectorIlNS5_9allocatorIlEEEE;
- _ZN7android2os17PersistableBundle14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17PersistableBundle15putDoubleVectorERKNS_8String16ERKNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZN7android2os17PersistableBundle15putStringVectorERKNS_8String16ERKNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZN7android2os17PersistableBundle16putBooleanVectorERKNS_8String16ERKNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZN7android2os17PersistableBundle19readFromParcelInnerEPKNS_6ParcelEm;
- _ZN7android2os17PersistableBundle20putPersistableBundleERKNS_8String16ERKS1_;
- _ZN7android2os17PersistableBundle5eraseERKNS_8String16E;
- _ZN7android2os17PersistableBundle6putIntERKNS_8String16Ei;
- _ZN7android2os17PersistableBundle7putLongERKNS_8String16El;
- _ZN7android2os17PersistableBundle9putDoubleERKNS_8String16Ed;
- _ZN7android2os17PersistableBundle9putStringERKNS_8String16ES4_;
- _ZN7android2os20ParcelFileDescriptor14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os20ParcelFileDescriptorC1ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC1Ev;
- _ZN7android2os20ParcelFileDescriptorC2ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC2Ev;
- _ZN7android2os20ParcelFileDescriptorD0Ev;
- _ZN7android2os20ParcelFileDescriptorD1Ev;
- _ZN7android2os20ParcelFileDescriptorD2Ev;
- _ZN7android4aerrE;
- _ZN7android4alogE;
- _ZN7android4aoutE;
- _ZN7android6binder20LazyServiceRegistrar10reRegisterEv;
- _ZN7android6binder20LazyServiceRegistrar11getInstanceEv;
- _ZN7android6binder20LazyServiceRegistrar12forcePersistEb;
- _ZN7android6binder20LazyServiceRegistrar13tryUnregisterEv;
- _ZN7android6binder20LazyServiceRegistrar15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEbi;
- _ZN7android6binder20LazyServiceRegistrar25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder20LazyServiceRegistrarC1Ev;
- _ZN7android6binder20LazyServiceRegistrarC2Ev;
- _ZN7android6binder6Status11fromStatusTEi;
- _ZN7android6binder6Status12setExceptionEiRKNS_7String8E;
- _ZN7android6binder6Status14readFromParcelERKNS_6ParcelE;
- _ZN7android6binder6Status14setFromStatusTEi;
- _ZN7android6binder6Status17exceptionToStringEi;
- _ZN7android6binder6Status17fromExceptionCodeEi;
- _ZN7android6binder6Status17fromExceptionCodeEiPKc;
- _ZN7android6binder6Status17fromExceptionCodeEiRKNS_7String8E;
- _ZN7android6binder6Status23setServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status24fromServiceSpecificErrorEi;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiPKc;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status2okEv;
- _ZN7android6binder6StatusC1Eii;
- _ZN7android6binder6StatusC1EiiRKNS_7String8E;
- _ZN7android6binder6StatusC2Eii;
- _ZN7android6binder6StatusC2EiiRKNS_7String8E;
- _ZN7android6binder8internal21ClientCounterCallback10reRegisterEv;
- _ZN7android6binder8internal21ClientCounterCallback12forcePersistEb;
- _ZN7android6binder8internal21ClientCounterCallback13tryUnregisterEv;
- _ZN7android6binder8internal21ClientCounterCallback15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEbi;
- _ZN7android6binder8internal21ClientCounterCallback25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder8internal21ClientCounterCallbackC1Ev;
- _ZN7android6binder8internal21ClientCounterCallbackC2Ev;
- _ZN7android6Parcel10appendFromEPKS0_mm;
- _ZN7android6Parcel10markForRpcERKNS_2spINS_10RpcSessionEEE;
- _ZN7android6Parcel10writeFloatEf;
- _ZN7android6Parcel10writeInt32Ei;
- _ZN7android6Parcel10writeInt64El;
- _ZN7android6Parcel11compareDataERKS0_;
- _ZN7android6Parcel11finishWriteEm;
- _ZN7android6Parcel11setDataSizeEm;
- _ZN7android6Parcel11writeDoubleEd;
- _ZN7android6Parcel11writeObjectERK18flat_binder_objectb;
- _ZN7android6Parcel11writeUint32Ej;
- _ZN7android6Parcel11writeUint64Em;
- _ZN7android6Parcel12pushAllowFdsEb;
- _ZN7android6Parcel12restartWriteEm;
- _ZN7android6Parcel12writeCStringEPKc;
- _ZN7android6Parcel12writeInplaceEm;
- _ZN7android6Parcel12writePointerEm;
- _ZN7android6Parcel12writeString8EPKcm;
- _ZN7android6Parcel12writeString8ERKNS_7String8E;
- _ZN7android6Parcel13continueWriteEm;
- _ZN7android6Parcel13flattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13markForBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13writeString16EPKDsm;
- _ZN7android6Parcel13writeString16ERKNS_8String16E;
- _ZN7android6Parcel13writeString16ERKNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZN7android6Parcel13writeString16ERKNSt3__18optionalINS_8String16EEE;
- _ZN7android6Parcel13writeUnpaddedEPKvm;
- _ZN7android6Parcel14acquireObjectsEv;
- _ZN7android6Parcel14freeDataNoInitEv;
- _ZN7android6Parcel14releaseObjectsEv;
- _ZN7android6Parcel14writeByteArrayEmPKh;
- _ZN7android6Parcel15restoreAllowFdsEb;
- _ZN7android6Parcel15setDataCapacityEm;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZN7android6Parcel15writeInt32ArrayEmPKi;
- _ZN7android6Parcel15writeParcelableERKNS_10ParcelableE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__110unique_ptrINS1_6vectorIlNS1_9allocatorIlEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__16vectorIlNS1_9allocatorIlEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__18optionalINS1_6vectorIlNS1_9allocatorIlEEEEEE;
- _ZN7android6Parcel16writeNoExceptionEv;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZN7android6Parcel17writeNativeHandleEPK13native_handle;
- _ZN7android6Parcel17writeStrongBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__110unique_ptrINS1_6vectorImNS1_9allocatorImEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__16vectorImNS1_9allocatorImEEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__18optionalINS1_6vectorImNS1_9allocatorImEEEEEE;
- _ZN7android6Parcel18getGlobalAllocSizeEv;
- _ZN7android6Parcel19finishFlattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel19getGlobalAllocCountEv;
- _ZN7android6Parcel19ipcSetDataReferenceEPKhmPKymPFvPS0_S2_mS4_mE;
- _ZN7android6Parcel19writeFileDescriptorEib;
- _ZN7android6Parcel19writeInterfaceTokenEPKDsm;
- _ZN7android6Parcel19writeInterfaceTokenERKNS_8String16E;
- _ZN7android6Parcel19writeString16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZN7android6Parcel20closeFileDescriptorsEv;
- _ZN7android6Parcel22writeDupFileDescriptorEi;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZN7android6Parcel25writeParcelFileDescriptorEib;
- _ZN7android6Parcel25writeUniqueFileDescriptorERKNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android6Parcel26writeRawNullableParcelableEPKNS_10ParcelableE;
- _ZN7android6Parcel27replaceCallingWorkSourceUidEj;
- _ZN7android6Parcel28writeDupParcelFileDescriptorEi;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZN7android6Parcel35writeDupImmutableBlobFileDescriptorEi;
- _ZN7android6Parcel4Blob4initEiPvmb;
- _ZN7android6Parcel4Blob5clearEv;
- _ZN7android6Parcel4Blob7releaseEv;
- _ZN7android6Parcel4BlobC1Ev;
- _ZN7android6Parcel4BlobC2Ev;
- _ZN7android6Parcel4BlobD1Ev;
- _ZN7android6Parcel4BlobD2Ev;
- _ZN7android6Parcel5writeEPKvm;
- _ZN7android6Parcel5writeERKNS0_26FlattenableHelperInterfaceE;
- _ZN7android6Parcel7setDataEPKhm;
- _ZN7android6Parcel8freeDataEv;
- _ZN7android6Parcel8growDataEm;
- _ZN7android6Parcel8setErrorEi;
- _ZN7android6Parcel9initStateEv;
- _ZN7android6Parcel9writeBlobEmbPNS0_12WritableBlobE;
- _ZN7android6Parcel9writeBoolEb;
- _ZN7android6Parcel9writeByteEa;
- _ZN7android6Parcel9writeCharEDs;
- _ZN7android6ParcelC1Ev;
- _ZN7android6ParcelC2Ev;
- _ZN7android6ParcelD1Ev;
- _ZN7android6ParcelD2Ev;
- _ZN7android7BBinder10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinder10pingBinderEv;
- _ZN7android7BBinder11getDebugPidEv;
- _ZN7android7BBinder11isInheritRtEv;
- _ZN7android7BBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android7BBinder11localBinderEv;
- _ZN7android7BBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android7BBinder12detachObjectEPKv;
- _ZN7android7BBinder12getExtensionEv;
- _ZN7android7BBinder12setExtensionERKNS_2spINS_7IBinderEEE;
- _ZN7android7BBinder12setInheritRtEb;
- _ZN7android7BBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android7BBinder15isRequestingSidEv;
- _ZN7android7BBinder16setRequestingSidEb;
- _ZN7android7BBinder17getOrCreateExtrasEv;
- _ZN7android7BBinder21getMinSchedulerPolicyEv;
- _ZN7android7BBinder21setMinSchedulerPolicyEii;
- _ZN7android7BBinder23getMinSchedulerPriorityEv;
- _ZN7android7BBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinderC1Ev;
- _ZN7android7BBinderC2Ev;
- _ZN7android7BBinderD0Ev;
- _ZN7android7BBinderD1Ev;
- _ZN7android7BBinderD2Ev;
- _ZN7android7content2pm18PackageChangeEvent14readFromParcelEPKNS_6ParcelE;
- _ZN7android7content2pm21IPackageManagerNative10descriptorE;
- _ZN7android7content2pm21IPackageManagerNative11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm21IPackageManagerNative12default_implE;
- _ZN7android7content2pm21IPackageManagerNative14getDefaultImplEv;
- _ZN7android7content2pm21IPackageManagerNative14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm21IPackageManagerNativeC2Ev;
- _ZN7android7content2pm21IPackageManagerNativeD0Ev;
- _ZN7android7content2pm21IPackageManagerNativeD1Ev;
- _ZN7android7content2pm21IPackageManagerNativeD2Ev;
- _ZN7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm22BnPackageManagerNativeC2Ev;
- _ZN7android7content2pm22BpPackageManagerNative14getAllPackagesEPNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative15getNamesForUidsERKNSt3__16vectorIiNS3_9allocatorIiEEEEPNS4_INS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEENS5_ISE_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative16getLocationFlagsERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPi;
- _ZN7android7content2pm22BpPackageManagerNative16hasSystemFeatureERKNS_8String16EiPb;
- _ZN7android7content2pm22BpPackageManagerNative19isPackageDebuggableERKNS_8String16EPb;
- _ZN7android7content2pm22BpPackageManagerNative22getInstallerForPackageERKNS_8String16EPNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative24getVersionCodeForPackageERKNS_8String16EPl;
- _ZN7android7content2pm22BpPackageManagerNative27hasSha256SigningCertificateERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEERKNS3_6vectorIhNS7_IhEEEEPb;
- _ZN7android7content2pm22BpPackageManagerNative28getModuleMetadataPackageNameEPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29getTargetSdkVersionForPackageERKNS_8String16EPi;
- _ZN7android7content2pm22BpPackageManagerNative29isAudioPlaybackCaptureAllowedERKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEPNS4_IbNS8_IbEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29registerPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNative31unregisterPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver10descriptorE;
- _ZN7android7content2pm22IPackageChangeObserver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver12default_implE;
- _ZN7android7content2pm22IPackageChangeObserver14getDefaultImplEv;
- _ZN7android7content2pm22IPackageChangeObserver14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm22IPackageChangeObserverC2Ev;
- _ZN7android7content2pm22IPackageChangeObserverD0Ev;
- _ZN7android7content2pm22IPackageChangeObserverD1Ev;
- _ZN7android7content2pm22IPackageChangeObserverD2Ev;
- _ZN7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm23BnPackageChangeObserverC2Ev;
- _ZN7android7content2pm23BpPackageChangeObserver16onPackageChangedERKNS1_18PackageChangeEventE;
- _ZN7android7content2pm23BpPackageChangeObserverC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm23BpPackageChangeObserverC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7HexDumpC1EPKvmm;
- _ZN7android7HexDumpC2EPKvmm;
- _ZN7android7IBinder11getDebugPidEPi;
- _ZN7android7IBinder11localBinderEv;
- _ZN7android7IBinder12getExtensionEPNS_2spIS0_EE;
- _ZN7android7IBinder12remoteBinderEv;
- _ZN7android7IBinder12shellCommandERKNS_2spIS0_EEiiiRNS_6VectorINS_8String16EEERKNS1_INS_14IShellCallbackEEERKNS1_INS_15IResultReceiverEEE;
- _ZN7android7IBinder19queryLocalInterfaceERKNS_8String16E;
- _ZN7android7IBinderC2Ev;
- _ZN7android7IBinderD0Ev;
- _ZN7android7IBinderD1Ev;
- _ZN7android7IBinderD2Ev;
- _ZN7android7IMemory10descriptorE;
- _ZN7android7IMemory11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7IMemory12default_implE;
- _ZN7android7IMemory14getDefaultImplEv;
- _ZN7android7IMemory14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android7IMemoryC2Ev;
- _ZN7android7IMemoryD0Ev;
- _ZN7android7IMemoryD1Ev;
- _ZN7android7IMemoryD2Ev;
- _ZN7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BnMemoryC2Ev;
- _ZN7android8BnMemoryD0Ev;
- _ZN7android8BnMemoryD1Ev;
- _ZN7android8BnMemoryD2Ev;
- _ZN7android8BpBinder10onFirstRefEv;
- _ZN7android8BpBinder10pingBinderEv;
- _ZN7android8BpBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android8BpBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android8BpBinder12detachObjectEPKv;
- _ZN7android8BpBinder12remoteBinderEv;
- _ZN7android8BpBinder12sendObituaryEv;
- _ZN7android8BpBinder12sTrackingMapE;
- _ZN7android8BpBinder13getCountByUidERNS_6VectorIjEES3_;
- _ZN7android8BpBinder13ObjectManager4killEv;
- _ZN7android8BpBinder13ObjectManager6attachEPKvPvS4_PFvS3_S4_S4_E;
- _ZN7android8BpBinder13ObjectManager6detachEPKv;
- _ZN7android8BpBinder13ObjectManagerC1Ev;
- _ZN7android8BpBinder13ObjectManagerC2Ev;
- _ZN7android8BpBinder13ObjectManagerD1Ev;
- _ZN7android8BpBinder13ObjectManagerD2Ev;
- _ZN7android8BpBinder13sTrackingLockE;
- _ZN7android8BpBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android8BpBinder14reportOneDeathERKNS0_8ObituaryE;
- _ZN7android8BpBinder14sLimitCallbackE;
- _ZN7android8BpBinder15onLastStrongRefEPKv;
- _ZN7android8BpBinder15sNumTrackedUidsE;
- _ZN7android8BpBinder16enableCountByUidEv;
- _ZN7android8BpBinder16setLimitCallbackEPFviE;
- _ZN7android8BpBinder17disableCountByUidEv;
- _ZN7android8BpBinder18sCountByUidEnabledE;
- _ZN7android8BpBinder19getBinderProxyCountEj;
- _ZN7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZN7android8BpBinder20setCountByUidEnabledEb;
- _ZN7android8BpBinder26sBinderProxyThrottleCreateE;
- _ZN7android8BpBinder29sBinderProxyCountLowWatermarkE;
- _ZN7android8BpBinder29setBinderProxyCountWatermarksEii;
- _ZN7android8BpBinder30sBinderProxyCountHighWatermarkE;
- _ZN7android8BpBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android8BpBinder6createEi;
- _ZN7android8BpBinder6createERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BpBinderC1EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC1EONS0_9RpcHandleE;
- _ZN7android8BpBinderC1EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderC2EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC2EONS0_9RpcHandleE;
- _ZN7android8BpBinderC2EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderD0Ev;
- _ZN7android8BpBinderD1Ev;
- _ZN7android8BpBinderD2Ev;
- _ZN7android8BpMemoryC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryD0Ev;
- _ZN7android8BpMemoryD1Ev;
- _ZN7android8BpMemoryD2Ev;
- _ZN7android8internal9Stability11getCategoryEPNS_7IBinderE;
- _ZN7android8internal9Stability11levelStringENS1_5LevelE;
- _ZN7android8internal9Stability13getLocalLevelEv;
- _ZN7android8internal9Stability15isDeclaredLevelENS1_5LevelE;
- _ZN7android8internal9Stability17debugLogStabilityERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability19markCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability22tryMarkCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability24requiresVintfDeclarationERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability25forceDowngradeToStabilityERKNS_2spINS_7IBinderEEENS1_5LevelE;
- _ZN7android8internal9Stability30forceDowngradeToLocalStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToSystemStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToVendorStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability5checkENS1_8CategoryENS1_5LevelE;
- _ZN7android8internal9Stability7setReprEPNS_7IBinderEij;
- _ZN7android8internal9Stability8Category11debugStringEv;
- _ZN7android8internal9Stability8markVndkEPNS_7IBinderE;
- _ZN7android8internal9Stability9markVintfEPNS_7IBinderE;
- _ZN7android8RpcState11CommandDataC1Em;
- _ZN7android8RpcState11CommandDataC2Em;
- _ZN7android8RpcState12countBindersEv;
- _ZN7android8RpcState12getSessionIdERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPi;
- _ZN7android8RpcState12waitForReplyERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPNS_6ParcelE;
- _ZN7android8RpcState13getMaxThreadsERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPm;
- _ZN7android8RpcState13getRootObjectERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState13sendDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressE;
- _ZN7android8RpcState15onBinderLeavingERKNS_2spINS_10RpcSessionEEERKNS1_INS_7IBinderEEEPNS_10RpcAddressE;
- _ZN7android8RpcState15processTransactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState16onBinderEnteringERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8RpcState16processDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState20getAndExecuteCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState20processServerCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState23processTransactInternalERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEENS0_11CommandDataE;
- _ZN7android8RpcState4dumpEv;
- _ZN7android8RpcState6rpcRecERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPvm;
- _ZN7android8RpcState7rpcSendERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPKvm;
- _ZN7android8RpcState8transactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressEjRKNS_6ParcelERKNS_2spINS_10RpcSessionEEEPSA_j;
- _ZN7android8RpcState9terminateEv;
- _ZN7android8RpcStateC1Ev;
- _ZN7android8RpcStateC2Ev;
- _ZN7android8RpcStateD1Ev;
- _ZN7android8RpcStateD2Ev;
- _ZN7android9BpRefBase10onFirstRefEv;
- _ZN7android9BpRefBase15onLastStrongRefEPKv;
- _ZN7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZN7android9BpRefBaseC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseD0Ev;
- _ZN7android9BpRefBaseD1Ev;
- _ZN7android9BpRefBaseD2Ev;
- _ZN7android9HeapCache10binderDiedERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCache10dump_heapsEv;
- _ZN7android9HeapCache8get_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9find_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCacheC1Ev;
- _ZN7android9HeapCacheC2Ev;
- _ZN7android9HeapCacheD0Ev;
- _ZN7android9HeapCacheD1Ev;
- _ZN7android9HeapCacheD2Ev;
- _ZN7android9hexStringEPKvm;
- _ZN7android9RpcServer12listSessionsEv;
- _ZN7android9RpcServer13getMaxThreadsEv;
- _ZN7android9RpcServer13getRootObjectEv;
- _ZN7android9RpcServer13releaseServerEv;
- _ZN7android9RpcServer13setMaxThreadsEm;
- _ZN7android9RpcServer13setRootObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android9RpcServer15setupInetServerEjPj;
- _ZN7android9RpcServer16setupVsockServerEj;
- _ZN7android9RpcServer17setRootObjectWeakERKNS_2wpINS_7IBinderEEE;
- _ZN7android9RpcServer17setupSocketServerERKNS_16RpcSocketAddressE;
- _ZN7android9RpcServer19establishConnectionEONS_2spIS0_EENS_4base14unique_fd_implINS4_13DefaultCloserEEE;
- _ZN7android9RpcServer19setupExternalServerENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android9RpcServer20onSessionTerminatingERKNS_2spINS_10RpcSessionEEE;
- _ZN7android9RpcServer21setupUnixDomainServerEPKc;
- _ZN7android9RpcServer24numUninitializedSessionsEv;
- _ZN7android9RpcServer4joinEv;
- _ZN7android9RpcServer4makeEv;
- _ZN7android9RpcServer61iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProductionEv;
- _ZN7android9RpcServer9acceptOneEv;
- _ZN7android9RpcServer9hasServerEv;
- _ZN7android9RpcServerC1Ev;
- _ZN7android9RpcServerC2Ev;
- _ZN7android9RpcServerD0Ev;
- _ZN7android9RpcServerD1Ev;
- _ZN7android9RpcServerD2Ev;
- _ZN7android9SingletonINS_15PermissionCacheEE11getInstanceEv;
- _ZN7android9SingletonINS_15PermissionCacheEE11hasInstanceEv;
- _ZN7android9SingletonINS_15PermissionCacheEE5sLockE;
- _ZN7android9SingletonINS_15PermissionCacheEE9sInstanceE;
- _ZN7android9SingletonINS_15PermissionCacheEEC1Ev;
- _ZN7android9SingletonINS_15PermissionCacheEEC2Ev;
- _ZN7android9SingletonINS_15PermissionCacheEED1Ev;
- _ZN7android9SingletonINS_15PermissionCacheEED2Ev;
- _ZN7androidlsERNS_10TextOutputERKNS_7HexDumpE;
- _ZN7androidlsERNS_10TextOutputERKNS_8TypeCodeE;
- _ZN7androidlsIA15_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA24_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA2_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA34_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA3_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA43_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA4_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA5_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA8_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA9_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIjEERNS_10TextOutputES2_RKT_;
- _ZN7androidlsImEERNS_10TextOutputES2_RKT_;
- _ZN7androidlsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERNS_10TextOutputES9_RKT_;
- _ZN7androidlsIPcEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIPvEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIyEERNS_10TextOutputES2_RKT_;
- _ZNK7android10MemoryBase9getMemoryEPlPm;
- _ZNK7android10RpcAddress13writeToParcelEPNS_6ParcelE;
- _ZNK7android10RpcAddress15viewRawEmbeddedEv;
- _ZNK7android10RpcAddress6isZeroEv;
- _ZNK7android10RpcAddress8toStringEv;
- _ZNK7android10RpcAddressltERKS0_;
- _ZNK7android11IMemoryHeap22getInterfaceDescriptorEv;
- _ZNK7android12BpMemoryHeap12assertMappedEv;
- _ZNK7android12BpMemoryHeap18assertReallyMappedEv;
- _ZNK7android12BpMemoryHeap7getBaseEv;
- _ZNK7android12BpMemoryHeap7getSizeEv;
- _ZNK7android12BpMemoryHeap8getFlagsEv;
- _ZNK7android12BpMemoryHeap9getHeapIDEv;
- _ZNK7android12BpMemoryHeap9getOffsetEv;
- _ZNK7android12MemoryDealer4dumpEPKc;
- _ZNK7android12MemoryDealer4heapEv;
- _ZNK7android12MemoryDealer9allocatorEv;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE10do_compareEPKvS5_;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE10do_destroyEPvm;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE12do_constructEPvm;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE15do_move_forwardEPvPKvm;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE16do_move_backwardEPvPKvm;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE7do_copyEPvPKvm;
- _ZNK7android12SortedVectorINS_15PermissionCache5EntryEE8do_splatEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_compareEPKvSA_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_destroyEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE12do_constructEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE15do_move_forwardEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE16do_move_backwardEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE7do_copyEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE8do_splatEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_compareES3_S3_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_destroyEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE12do_constructEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE15do_move_forwardEPvS3_m;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE16do_move_backwardEPvS3_m;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE7do_copyEPvS3_m;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE8do_splatEPvS3_m;
- _ZNK7android12SortedVectorINS_8String16EE10do_compareEPKvS4_;
- _ZNK7android12SortedVectorINS_8String16EE10do_destroyEPvm;
- _ZNK7android12SortedVectorINS_8String16EE12do_constructEPvm;
- _ZNK7android12SortedVectorINS_8String16EE15do_move_forwardEPvPKvm;
- _ZNK7android12SortedVectorINS_8String16EE16do_move_backwardEPvPKvm;
- _ZNK7android12SortedVectorINS_8String16EE7do_copyEPvPKvm;
- _ZNK7android12SortedVectorINS_8String16EE8do_splatEPvPKvm;
- _ZNK7android14IPCThreadState13getCallingPidEv;
- _ZNK7android14IPCThreadState13getCallingSidEv;
- _ZNK7android14IPCThreadState13getCallingUidEv;
- _ZNK7android14IPCThreadState18getCallRestrictionEv;
- _ZNK7android14IPCThreadState19getStrictModePolicyEv;
- _ZNK7android14IPCThreadState22getServingStackPointerEv;
- _ZNK7android14IPCThreadState23getCallingWorkSourceUidEv;
- _ZNK7android14IPCThreadState25shouldPropagateWorkSourceEv;
- _ZNK7android14IPCThreadState29getLastTransactionBinderFlagsEv;
- _ZNK7android14IShellCallback22getInterfaceDescriptorEv;
- _ZNK7android14MemoryHeapBase7getBaseEv;
- _ZNK7android14MemoryHeapBase7getSizeEv;
- _ZNK7android14MemoryHeapBase8getFlagsEv;
- _ZNK7android14MemoryHeapBase9getDeviceEv;
- _ZNK7android14MemoryHeapBase9getHeapIDEv;
- _ZNK7android14MemoryHeapBase9getOffsetEv;
- _ZNK7android15IResultReceiver22getInterfaceDescriptorEv;
- _ZNK7android15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android15PermissionCache5checkEPbRKNS_8String16Ej;
- _ZNK7android18BufferedTextOutput9getBufferEv;
- _ZNK7android18ServiceManagerShim10getServiceERKNS_8String16E;
- _ZNK7android18ServiceManagerShim12checkServiceERKNS_8String16E;
- _ZNK7android21IPermissionController22getInterfaceDescriptorEv;
- _ZNK7android22SimpleBestFitAllocator4dumpEPKc;
- _ZNK7android22SimpleBestFitAllocator4dumpERNS_7String8EPKc;
- _ZNK7android22SimpleBestFitAllocator4sizeEv;
- _ZNK7android22SimpleBestFitAllocator6dump_lEPKc;
- _ZNK7android22SimpleBestFitAllocator6dump_lERNS_7String8EPKc;
- _ZNK7android2os15IClientCallback22getInterfaceDescriptorEv;
- _ZNK7android2os15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android2os16IServiceCallback22getInterfaceDescriptorEv;
- _ZNK7android2os16ParcelableHolder13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os16ServiceDebugInfo13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle10getBooleanERKNS_8String16EPb;
- _ZNK7android2os17PersistableBundle10getIntKeysEv;
- _ZNK7android2os17PersistableBundle11getLongKeysEv;
- _ZNK7android2os17PersistableBundle12getIntVectorERKNS_8String16EPNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZNK7android2os17PersistableBundle13getDoubleKeysEv;
- _ZNK7android2os17PersistableBundle13getLongVectorERKNS_8String16EPNSt3__16vectorIlNS5_9allocatorIlEEEE;
- _ZNK7android2os17PersistableBundle13getStringKeysEv;
- _ZNK7android2os17PersistableBundle13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle14getBooleanKeysEv;
- _ZNK7android2os17PersistableBundle15getDoubleVectorERKNS_8String16EPNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZNK7android2os17PersistableBundle15getStringVectorERKNS_8String16EPNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZNK7android2os17PersistableBundle16getBooleanVectorERKNS_8String16EPNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZNK7android2os17PersistableBundle16getIntVectorKeysEv;
- _ZNK7android2os17PersistableBundle17getLongVectorKeysEv;
- _ZNK7android2os17PersistableBundle18writeToParcelInnerEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle19getDoubleVectorKeysEv;
- _ZNK7android2os17PersistableBundle19getStringVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getBooleanVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getPersistableBundleERKNS_8String16EPS1_;
- _ZNK7android2os17PersistableBundle24getPersistableBundleKeysEv;
- _ZNK7android2os17PersistableBundle4sizeEv;
- _ZNK7android2os17PersistableBundle5emptyEv;
- _ZNK7android2os17PersistableBundle6getIntERKNS_8String16EPi;
- _ZNK7android2os17PersistableBundle7getLongERKNS_8String16EPl;
- _ZNK7android2os17PersistableBundle9getDoubleERKNS_8String16EPd;
- _ZNK7android2os17PersistableBundle9getStringERKNS_8String16EPS2_;
- _ZNK7android2os20ParcelFileDescriptor13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status9toString8Ev;
- _ZNK7android6Parcel10errorCheckEv;
- _ZNK7android6Parcel10ipcObjectsEv;
- _ZNK7android6Parcel10readDoubleEPd;
- _ZNK7android6Parcel10readDoubleEv;
- _ZNK7android6Parcel10readObjectEb;
- _ZNK7android6Parcel10readUint32EPj;
- _ZNK7android6Parcel10readUint32Ev;
- _ZNK7android6Parcel10readUint64EPm;
- _ZNK7android6Parcel10readUint64Ev;
- _ZNK7android6Parcel10scanForFdsEv;
- _ZNK7android6Parcel11ipcDataSizeEv;
- _ZNK7android6Parcel11readCStringEv;
- _ZNK7android6Parcel11readInplaceEm;
- _ZNK7android6Parcel11readPointerEPm;
- _ZNK7android6Parcel11readPointerEv;
- _ZNK7android6Parcel11readString8EPNS_7String8E;
- _ZNK7android6Parcel11readString8Ev;
- _ZNK7android6Parcel12dataCapacityEv;
- _ZNK7android6Parcel12dataPositionEv;
- _ZNK7android6Parcel12objectsCountEv;
- _ZNK7android6Parcel12readString16EPNS_8String16E;
- _ZNK7android6Parcel12readString16EPNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZNK7android6Parcel12readString16EPNSt3__18optionalINS_8String16EEE;
- _ZNK7android6Parcel12readString16Ev;
- _ZNK7android6Parcel13markSensitiveEv;
- _ZNK7android6Parcel14checkInterfaceEPNS_7IBinderE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZNK7android6Parcel14readParcelableEPNS_10ParcelableE;
- _ZNK7android6Parcel15ipcObjectsCountEv;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__110unique_ptrINS1_6vectorIlNS1_9allocatorIlEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__16vectorIlNS1_9allocatorIlEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__18optionalINS1_6vectorIlNS1_9allocatorIlEEEEEE;
- _ZNK7android6Parcel15setDataPositionEm;
- _ZNK7android6Parcel15unflattenBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16enforceInterfaceEPKDsmPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16enforceInterfaceERKNS_8String16EPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZNK7android6Parcel16readNativeHandleEv;
- _ZNK7android6Parcel16readStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16readStrongBinderEv;
- _ZNK7android6Parcel16readStrongBinderINS_2os15IClientCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_2os16IServiceCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_7content2pm22IPackageChangeObserverEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__110unique_ptrINS1_6vectorImNS1_9allocatorImEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__16vectorImNS1_9allocatorImEEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__18optionalINS1_6vectorImNS1_9allocatorImEEEEEE;
- _ZNK7android6Parcel16validateReadDataEm;
- _ZNK7android6Parcel17getBlobAshmemSizeEv;
- _ZNK7android6Parcel17getOpenAshmemSizeEv;
- _ZNK7android6Parcel17readExceptionCodeEv;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZNK7android6Parcel18hasFileDescriptorsEv;
- _ZNK7android6Parcel18readFileDescriptorEv;
- _ZNK7android6Parcel18readString16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZNK7android6Parcel18readString8InplaceEPm;
- _ZNK7android6Parcel19readString16InplaceEPm;
- _ZNK7android6Parcel21finishUnflattenBinderERKNS_2spINS_7IBinderEEEPS3_;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZNK7android6Parcel24readCallingWorkSourceUidEv;
- _ZNK7android6Parcel24readNullableStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel24readParcelFileDescriptorEv;
- _ZNK7android6Parcel24readUniqueFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZNK7android6Parcel30readUniqueParcelFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel37updateWorkSourceRequestHeaderPositionEv;
- _ZNK7android6Parcel4dataEv;
- _ZNK7android6Parcel4readEPvm;
- _ZNK7android6Parcel4readERNS0_26FlattenableHelperInterfaceE;
- _ZNK7android6Parcel5printERNS_10TextOutputEj;
- _ZNK7android6Parcel7ipcDataEv;
- _ZNK7android6Parcel8allowFdsEv;
- _ZNK7android6Parcel8dataSizeEv;
- _ZNK7android6Parcel8isForRpcEv;
- _ZNK7android6Parcel8readBlobEmPNS0_12ReadableBlobE;
- _ZNK7android6Parcel8readBoolEPb;
- _ZNK7android6Parcel8readBoolEv;
- _ZNK7android6Parcel8readByteEPa;
- _ZNK7android6Parcel8readByteEv;
- _ZNK7android6Parcel8readCharEPDs;
- _ZNK7android6Parcel8readCharEv;
- _ZNK7android6Parcel9dataAvailEv;
- _ZNK7android6Parcel9readFloatEPf;
- _ZNK7android6Parcel9readFloatEv;
- _ZNK7android6Parcel9readInt32EPi;
- _ZNK7android6Parcel9readInt32Ev;
- _ZNK7android6Parcel9readInt64EPl;
- _ZNK7android6Parcel9readInt64Ev;
- _ZNK7android6VectorIiE10do_destroyEPvm;
- _ZNK7android6VectorIiE12do_constructEPvm;
- _ZNK7android6VectorIiE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIiE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIiE7do_copyEPvPKvm;
- _ZNK7android6VectorIiE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE10do_destroyEPvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE12do_constructEPvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE10do_destroyEPvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE12do_constructEPvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE10do_destroyEPvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE12do_constructEPvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_8String16EE10do_destroyEPvm;
- _ZNK7android6VectorINS_8String16EE12do_constructEPvm;
- _ZNK7android6VectorINS_8String16EE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_8String16EE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_8String16EE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_8String16EE8do_splatEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE10do_destroyEPvm;
- _ZNK7android6VectorIPNS_7BBinderEE12do_constructEPvm;
- _ZNK7android6VectorIPNS_7BBinderEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE7do_copyEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE8do_splatEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE10do_destroyEPvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE12do_constructEPvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE7do_copyEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE8do_splatEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE10do_destroyEPvm;
- _ZNK7android6VectorIPNS_7RefBaseEE12do_constructEPvm;
- _ZNK7android6VectorIPNS_7RefBaseEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE7do_copyEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE8do_splatEPvPKvm;
- _ZNK7android7BBinder10findObjectEPKv;
- _ZNK7android7BBinder13isBinderAliveEv;
- _ZNK7android7BBinder22getInterfaceDescriptorEv;
- _ZNK7android7content2pm18PackageChangeEvent13writeToParcelEPNS_6ParcelE;
- _ZNK7android7content2pm21IPackageManagerNative22getInterfaceDescriptorEv;
- _ZNK7android7content2pm22IPackageChangeObserver22getInterfaceDescriptorEv;
- _ZNK7android7IBinder13checkSubclassEPKv;
- _ZNK7android7IMemory11fastPointerERKNS_2spINS_7IBinderEEEl;
- _ZNK7android7IMemory15unsecurePointerEv;
- _ZNK7android7IMemory22getInterfaceDescriptorEv;
- _ZNK7android7IMemory4sizeEv;
- _ZNK7android7IMemory6offsetEv;
- _ZNK7android7IMemory7pointerEv;
- _ZNK7android8BpBinder10findObjectEPKv;
- _ZNK7android8BpBinder10rpcAddressEv;
- _ZNK7android8BpBinder10rpcSessionEv;
- _ZNK7android8BpBinder11isRpcBinderEv;
- _ZNK7android8BpBinder12binderHandleEv;
- _ZNK7android8BpBinder13isBinderAliveEv;
- _ZNK7android8BpBinder13ObjectManager4findEPKv;
- _ZNK7android8BpBinder18isDescriptorCachedEv;
- _ZNK7android8BpBinder22getInterfaceDescriptorEv;
- _ZNK7android8BpMemory9getMemoryEPlPm;
- _ZTCN7android10AllocationE0_NS_10IInterfaceE;
- _ZTCN7android10AllocationE0_NS_10MemoryBaseE;
- _ZTCN7android10AllocationE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10AllocationE0_NS_7IMemoryE;
- _ZTCN7android10AllocationE0_NS_8BnMemoryE;
- _ZTCN7android10AllocationE8_NS_7BBinderE;
- _ZTCN7android10AllocationE8_NS_7IBinderE;
- _ZTCN7android10MemoryBaseE0_NS_10IInterfaceE;
- _ZTCN7android10MemoryBaseE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10MemoryBaseE0_NS_7IMemoryE;
- _ZTCN7android10MemoryBaseE0_NS_8BnMemoryE;
- _ZTCN7android10MemoryBaseE8_NS_7BBinderE;
- _ZTCN7android10MemoryBaseE8_NS_7IBinderE;
- _ZTCN7android10PoolThreadE0_NS_6ThreadE;
- _ZTCN7android11IMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BnMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BnMemoryHeapE8_NS_7BBinderE;
- _ZTCN7android12BnMemoryHeapE8_NS_7IBinderE;
- _ZTCN7android12BpMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BpMemoryHeapE0_NS_11BpInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BpMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BpMemoryHeapE8_NS_9BpRefBaseE;
- _ZTCN7android14IShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE64_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE64_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android14MemoryHeapBaseE64_NS_11IMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE64_NS_12BnMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE72_NS_7BBinderE;
- _ZTCN7android14MemoryHeapBaseE72_NS_7IBinderE;
- _ZTCN7android15BnShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BnShellCallbackE0_NS_11BnInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BnShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BnShellCallbackE8_NS_7BBinderE;
- _ZTCN7android15BnShellCallbackE8_NS_7IBinderE;
- _ZTCN7android15BpShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BpShellCallbackE0_NS_11BpInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BpShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BpShellCallbackE8_NS_9BpRefBaseE;
- _ZTCN7android15IResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_11BnInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BnResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BnResultReceiverE8_NS_7BBinderE;
- _ZTCN7android16BnResultReceiverE8_NS_7IBinderE;
- _ZTCN7android16BpResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BpResultReceiverE0_NS_11BpInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BpResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BpResultReceiverE8_NS_9BpRefBaseE;
- _ZTCN7android18ServiceManagerShimE0_NS_10IInterfaceE;
- _ZTCN7android18ServiceManagerShimE0_NS_15IServiceManagerE;
- _ZTCN7android21IPermissionControllerE0_NS_10IInterfaceE;
- _ZTCN7android22BnPermissionControllerE0_NS_10IInterfaceE;
- _ZTCN7android22BnPermissionControllerE0_NS_11BnInterfaceINS_21IPermissionControllerEEE;
- _ZTCN7android22BnPermissionControllerE0_NS_21IPermissionControllerE;
- _ZTCN7android22BnPermissionControllerE8_NS_7BBinderE;
- _ZTCN7android22BnPermissionControllerE8_NS_7IBinderE;
- _ZTCN7android22BpPermissionControllerE0_NS_10IInterfaceE;
- _ZTCN7android22BpPermissionControllerE0_NS_11BpInterfaceINS_21IPermissionControllerEEE;
- _ZTCN7android22BpPermissionControllerE0_NS_21IPermissionControllerE;
- _ZTCN7android22BpPermissionControllerE8_NS_9BpRefBaseE;
- _ZTCN7android2os15IClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BnClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS_11BnInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BnClientCallbackE8_NS_7BBinderE;
- _ZTCN7android2os16BnClientCallbackE8_NS_7IBinderE;
- _ZTCN7android2os16BnServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BnServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnServiceManagerE0_NS_11BnInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BnServiceManagerE8_NS_7BBinderE;
- _ZTCN7android2os16BnServiceManagerE8_NS_7IBinderE;
- _ZTCN7android2os16BpClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BpClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpClientCallbackE0_NS_11BpInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BpClientCallbackE8_NS_9BpRefBaseE;
- _ZTCN7android2os16BpServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BpServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpServiceManagerE0_NS_11BpInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BpServiceManagerE8_NS_9BpRefBaseE;
- _ZTCN7android2os16IServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_11BnInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BnServiceCallbackE8_NS_7BBinderE;
- _ZTCN7android2os17BnServiceCallbackE8_NS_7IBinderE;
- _ZTCN7android2os17BpServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_11BpInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BpServiceCallbackE8_NS_9BpRefBaseE;
- _ZTCN7android7BBinderE0_NS_7IBinderE;
- _ZTCN7android7content2pm21IPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_11BnInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE8_NS_7BBinderE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE8_NS_7IBinderE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_11BpInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE8_NS_9BpRefBaseE;
- _ZTCN7android7content2pm22IPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_11BnInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE8_NS_7BBinderE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE8_NS_7IBinderE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_11BpInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE8_NS_9BpRefBaseE;
- _ZTCN7android7IMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BnMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BnMemoryE8_NS_7BBinderE;
- _ZTCN7android8BnMemoryE8_NS_7IBinderE;
- _ZTCN7android8BpBinderE0_NS_7IBinderE;
- _ZTCN7android8BpMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BpMemoryE0_NS_11BpInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BpMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BpMemoryE8_NS_9BpRefBaseE;
- _ZTCN7android9HeapCacheE0_NS_7IBinder14DeathRecipientE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_13basic_istreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_14basic_iostreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE16_NS_13basic_ostreamIcS2_EE;
- _ZThn8_N7android10AllocationD0Ev;
- _ZThn8_N7android10AllocationD1Ev;
- _ZThn8_N7android10MemoryBaseD0Ev;
- _ZThn8_N7android10MemoryBaseD1Ev;
- _ZThn8_N7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android12BnMemoryHeapD0Ev;
- _ZThn8_N7android12BnMemoryHeapD1Ev;
- _ZThn8_N7android12BpMemoryHeapD0Ev;
- _ZThn8_N7android12BpMemoryHeapD1Ev;
- _ZThn8_N7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android22BnPermissionController10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn8_N7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn8_N7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn8_N7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn8_N7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn8_N7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android8BnMemoryD0Ev;
- _ZThn8_N7android8BnMemoryD1Ev;
- _ZThn8_N7android8BpMemoryD0Ev;
- _ZThn8_N7android8BpMemoryD1Ev;
- _ZTTN7android10AllocationE;
- _ZTTN7android10IInterfaceE;
- _ZTTN7android10MemoryBaseE;
- _ZTTN7android10PoolThreadE;
- _ZTTN7android10RpcSessionE;
- _ZTTN7android11IMemoryHeapE;
- _ZTTN7android12BnMemoryHeapE;
- _ZTTN7android12BpMemoryHeapE;
- _ZTTN7android12ProcessStateE;
- _ZTTN7android14IShellCallbackE;
- _ZTTN7android14MemoryHeapBaseE;
- _ZTTN7android15BnShellCallbackE;
- _ZTTN7android15BpShellCallbackE;
- _ZTTN7android15IResultReceiverE;
- _ZTTN7android15IServiceManagerE;
- _ZTTN7android16BnResultReceiverE;
- _ZTTN7android16BpResultReceiverE;
- _ZTTN7android18ServiceManagerShimE;
- _ZTTN7android21IPermissionControllerE;
- _ZTTN7android22BnPermissionControllerE;
- _ZTTN7android22BpPermissionControllerE;
- _ZTTN7android2os15IClientCallbackE;
- _ZTTN7android2os15IServiceManagerE;
- _ZTTN7android2os16BnClientCallbackE;
- _ZTTN7android2os16BnServiceManagerE;
- _ZTTN7android2os16BpClientCallbackE;
- _ZTTN7android2os16BpServiceManagerE;
- _ZTTN7android2os16IServiceCallbackE;
- _ZTTN7android2os17BnServiceCallbackE;
- _ZTTN7android2os17BpServiceCallbackE;
- _ZTTN7android7BBinderE;
- _ZTTN7android7content2pm21IPackageManagerNativeE;
- _ZTTN7android7content2pm22BnPackageManagerNativeE;
- _ZTTN7android7content2pm22BpPackageManagerNativeE;
- _ZTTN7android7content2pm22IPackageChangeObserverE;
- _ZTTN7android7content2pm23BnPackageChangeObserverE;
- _ZTTN7android7content2pm23BpPackageChangeObserverE;
- _ZTTN7android7IBinderE;
- _ZTTN7android7IMemoryE;
- _ZTTN7android8BnMemoryE;
- _ZTTN7android8BpBinderE;
- _ZTTN7android8BpMemoryE;
- _ZTTN7android9BpRefBaseE;
- _ZTTN7android9HeapCacheE;
- _ZTTN7android9RpcServerE;
- _ZTTNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE;
- _ZTv0_n24_N7android10AllocationD0Ev;
- _ZTv0_n24_N7android10AllocationD1Ev;
- _ZTv0_n24_N7android10IInterfaceD0Ev;
- _ZTv0_n24_N7android10IInterfaceD1Ev;
- _ZTv0_n24_N7android10MemoryBaseD0Ev;
- _ZTv0_n24_N7android10MemoryBaseD1Ev;
- _ZTv0_n24_N7android10RpcSessionD0Ev;
- _ZTv0_n24_N7android10RpcSessionD1Ev;
- _ZTv0_n24_N7android11IMemoryHeapD0Ev;
- _ZTv0_n24_N7android11IMemoryHeapD1Ev;
- _ZTv0_n24_N7android12BnMemoryHeapD0Ev;
- _ZTv0_n24_N7android12BnMemoryHeapD1Ev;
- _ZTv0_n24_N7android12BpMemoryHeapD0Ev;
- _ZTv0_n24_N7android12BpMemoryHeapD1Ev;
- _ZTv0_n24_N7android12ProcessStateD0Ev;
- _ZTv0_n24_N7android12ProcessStateD1Ev;
- _ZTv0_n24_N7android14IShellCallbackD0Ev;
- _ZTv0_n24_N7android14IShellCallbackD1Ev;
- _ZTv0_n24_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n24_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n24_N7android15IResultReceiverD0Ev;
- _ZTv0_n24_N7android15IResultReceiverD1Ev;
- _ZTv0_n24_N7android15IServiceManagerD0Ev;
- _ZTv0_n24_N7android15IServiceManagerD1Ev;
- _ZTv0_n24_N7android21IPermissionControllerD0Ev;
- _ZTv0_n24_N7android21IPermissionControllerD1Ev;
- _ZTv0_n24_N7android2os15IClientCallbackD0Ev;
- _ZTv0_n24_N7android2os15IClientCallbackD1Ev;
- _ZTv0_n24_N7android2os15IServiceManagerD0Ev;
- _ZTv0_n24_N7android2os15IServiceManagerD1Ev;
- _ZTv0_n24_N7android2os16IServiceCallbackD0Ev;
- _ZTv0_n24_N7android2os16IServiceCallbackD1Ev;
- _ZTv0_n24_N7android7BBinderD0Ev;
- _ZTv0_n24_N7android7BBinderD1Ev;
- _ZTv0_n24_N7android7content2pm21IPackageManagerNativeD0Ev;
- _ZTv0_n24_N7android7content2pm21IPackageManagerNativeD1Ev;
- _ZTv0_n24_N7android7content2pm22IPackageChangeObserverD0Ev;
- _ZTv0_n24_N7android7content2pm22IPackageChangeObserverD1Ev;
- _ZTv0_n24_N7android7IBinderD0Ev;
- _ZTv0_n24_N7android7IBinderD1Ev;
- _ZTv0_n24_N7android7IMemoryD0Ev;
- _ZTv0_n24_N7android7IMemoryD1Ev;
- _ZTv0_n24_N7android8BnMemoryD0Ev;
- _ZTv0_n24_N7android8BnMemoryD1Ev;
- _ZTv0_n24_N7android8BpBinderD0Ev;
- _ZTv0_n24_N7android8BpBinderD1Ev;
- _ZTv0_n24_N7android8BpMemoryD0Ev;
- _ZTv0_n24_N7android8BpMemoryD1Ev;
- _ZTv0_n24_N7android9BpRefBaseD0Ev;
- _ZTv0_n24_N7android9BpRefBaseD1Ev;
- _ZTv0_n24_N7android9HeapCacheD0Ev;
- _ZTv0_n24_N7android9HeapCacheD1Ev;
- _ZTv0_n24_N7android9RpcServerD0Ev;
- _ZTv0_n24_N7android9RpcServerD1Ev;
- _ZTv0_n32_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n32_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n32_N7android8BpBinder10onFirstRefEv;
- _ZTv0_n32_N7android9BpRefBase10onFirstRefEv;
- _ZTv0_n40_N7android8BpBinder15onLastStrongRefEPKv;
- _ZTv0_n40_N7android9BpRefBase15onLastStrongRefEPKv;
- _ZTv0_n48_N7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZTv0_n48_N7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZTv0_n56_NK7android14MemoryHeapBase9getHeapIDEv;
- _ZTv0_n64_NK7android14MemoryHeapBase7getBaseEv;
- _ZTv0_n72_NK7android14MemoryHeapBase7getSizeEv;
- _ZTv0_n80_NK7android14MemoryHeapBase8getFlagsEv;
- _ZTv0_n88_NK7android14MemoryHeapBase9getOffsetEv;
- _ZTVN7android10AllocationE;
- _ZTVN7android10IInterfaceE;
- _ZTVN7android10MemoryBaseE;
- _ZTVN7android10PoolThreadE;
- _ZTVN7android10RpcSession13RpcConnectionE;
- _ZTVN7android10RpcSessionE;
- _ZTVN7android10TextOutputE;
- _ZTVN7android11IMemoryHeapE;
- _ZTVN7android12BnMemoryHeapE;
- _ZTVN7android12BpMemoryHeapE;
- _ZTVN7android12FdTextOutputE;
- _ZTVN7android12MemoryDealerE;
- _ZTVN7android12ProcessStateE;
- _ZTVN7android12SortedVectorINS_15PermissionCache5EntryEEE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEEE;
- _ZTVN7android12SortedVectorINS_8String16EEE;
- _ZTVN7android13LogTextOutputE;
- _ZTVN7android14IShellCallbackE;
- _ZTVN7android14MemoryHeapBaseE;
- _ZTVN7android15BnShellCallbackE;
- _ZTVN7android15BpShellCallbackE;
- _ZTVN7android15IResultReceiverE;
- _ZTVN7android15IServiceManagerE;
- _ZTVN7android16BnResultReceiverE;
- _ZTVN7android16BpResultReceiverE;
- _ZTVN7android17InetSocketAddressE;
- _ZTVN7android17UnixSocketAddressE;
- _ZTVN7android18BufferedTextOutput11BufferStateE;
- _ZTVN7android18BufferedTextOutputE;
- _ZTVN7android18ServiceManagerShimE;
- _ZTVN7android18VsockSocketAddressE;
- _ZTVN7android21IPermissionControllerE;
- _ZTVN7android22BnPermissionControllerE;
- _ZTVN7android22BpPermissionControllerE;
- _ZTVN7android2os15IClientCallbackE;
- _ZTVN7android2os15IServiceManagerE;
- _ZTVN7android2os16BnClientCallbackE;
- _ZTVN7android2os16BnServiceManagerE;
- _ZTVN7android2os16BpClientCallbackE;
- _ZTVN7android2os16BpServiceManagerE;
- _ZTVN7android2os16IServiceCallbackE;
- _ZTVN7android2os16ParcelableHolderE;
- _ZTVN7android2os16ServiceDebugInfoE;
- _ZTVN7android2os17BnServiceCallbackE;
- _ZTVN7android2os17BpServiceCallbackE;
- _ZTVN7android2os17PersistableBundleE;
- _ZTVN7android2os20ParcelFileDescriptorE;
- _ZTVN7android6VectorIiEE;
- _ZTVN7android6VectorINS_12ProcessState12handle_entryEEE;
- _ZTVN7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEEE;
- _ZTVN7android6VectorINS_8BpBinder8ObituaryEEE;
- _ZTVN7android6VectorINS_8String16EEE;
- _ZTVN7android6VectorIPNS_7BBinderEEE;
- _ZTVN7android6VectorIPNS_7RefBase12weakref_typeEEE;
- _ZTVN7android6VectorIPNS_7RefBaseEEE;
- _ZTVN7android7BBinderE;
- _ZTVN7android7content2pm18PackageChangeEventE;
- _ZTVN7android7content2pm21IPackageManagerNativeE;
- _ZTVN7android7content2pm22BnPackageManagerNativeE;
- _ZTVN7android7content2pm22BpPackageManagerNativeE;
- _ZTVN7android7content2pm22IPackageChangeObserverE;
- _ZTVN7android7content2pm23BnPackageChangeObserverE;
- _ZTVN7android7content2pm23BpPackageChangeObserverE;
- _ZTVN7android7IBinderE;
- _ZTVN7android7IMemoryE;
- _ZTVN7android8BnMemoryE;
- _ZTVN7android8BpBinderE;
- _ZTVN7android8BpMemoryE;
- _ZTVN7android9BpRefBaseE;
- _ZTVN7android9HeapCacheE;
- _ZTVN7android9RpcServerE;
- _ZTvn8_n32_N7android14MemoryHeapBaseD0Ev;
- _ZTvn8_n32_N7android14MemoryHeapBaseD1Ev;
- local:
- *;
-};
diff --git a/libs/binder/libbinder.arm64.vendor.map b/libs/binder/libbinder.arm64.vendor.map
deleted file mode 100644
index df6aa66..0000000
--- a/libs/binder/libbinder.arm64.vendor.map
+++ /dev/null
@@ -1,1320 +0,0 @@
-# b/190148312: Populate with correct list of ABI symbols
-LIBBINDER {
- global:
- getBinderKernelReferences;
- kDefaultDriver;
- _ZN7android10AllocationC1ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEElm;
- _ZN7android10AllocationC2ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEElm;
- _ZN7android10AllocationD0Ev;
- _ZN7android10AllocationD1Ev;
- _ZN7android10AllocationD2Ev;
- _ZN7android10IInterface8asBinderEPKS0_;
- _ZN7android10IInterface8asBinderERKNS_2spIS0_EE;
- _ZN7android10IInterfaceC2Ev;
- _ZN7android10IInterfaceD0Ev;
- _ZN7android10IInterfaceD1Ev;
- _ZN7android10IInterfaceD2Ev;
- _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElm;
- _ZN7android10MemoryBaseC2ERKNS_2spINS_11IMemoryHeapEEElm;
- _ZN7android10MemoryBaseD0Ev;
- _ZN7android10MemoryBaseD1Ev;
- _ZN7android10MemoryBaseD2Ev;
- _ZN7android10RpcAddress14readFromParcelERKNS_6ParcelE;
- _ZN7android10RpcAddress15fromRawEmbeddedEPKNS_14RpcWireAddressE;
- _ZN7android10RpcAddress4zeroEv;
- _ZN7android10RpcAddress6uniqueEv;
- _ZN7android10RpcAddressC1Ev;
- _ZN7android10RpcAddressC2Ev;
- _ZN7android10RpcAddressD1Ev;
- _ZN7android10RpcAddressD2Ev;
- _ZN7android10RpcSession12setForServerERKNS_2wpINS_9RpcServerEEEi;
- _ZN7android10RpcSession13getRootObjectEv;
- _ZN7android10RpcSession13sendDecStrongERKNS_10RpcAddressE;
- _ZN7android10RpcSession15setupInetClientEPKcj;
- _ZN7android10RpcSession15terminateLockedEv;
- _ZN7android10RpcSession16setupVsockClientEjj;
- _ZN7android10RpcSession17setupSocketClientERKNS_16RpcSocketAddressE;
- _ZN7android10RpcSession19addClientConnectionENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession19ExclusiveConnection14findConnectionEiPNS_2spINS0_13RpcConnectionEEES5_RNSt3__16vectorIS4_NS6_9allocatorIS4_EEEEm;
- _ZN7android10RpcSession19ExclusiveConnectionC1ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionC2ERKNS_2spIS0_EENS0_13ConnectionUseE;
- _ZN7android10RpcSession19ExclusiveConnectionD1Ev;
- _ZN7android10RpcSession19ExclusiveConnectionD2Ev;
- _ZN7android10RpcSession19getRemoteMaxThreadsEPm;
- _ZN7android10RpcSession20setupOneSocketClientERKNS_16RpcSocketAddressEi;
- _ZN7android10RpcSession21setupUnixDomainClientEPKc;
- _ZN7android10RpcSession22addNullDebuggingClientEv;
- _ZN7android10RpcSession22removeServerConnectionERKNS_2spINS0_13RpcConnectionEEE;
- _ZN7android10RpcSession24assignServerToThisThreadENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4joinENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android10RpcSession4makeEv;
- _ZN7android10RpcSession6readIdEv;
- _ZN7android10RpcSession6serverEv;
- _ZN7android10RpcSession7preJoinENSt3__16threadE;
- _ZN7android10RpcSession8transactERKNS_10RpcAddressEjRKNS_6ParcelEPS4_j;
- _ZN7android10RpcSessionC1Ev;
- _ZN7android10RpcSessionC2Ev;
- _ZN7android10RpcSessionD0Ev;
- _ZN7android10RpcSessionD1Ev;
- _ZN7android10RpcSessionD2Ev;
- _ZN7android10TextOutputC2Ev;
- _ZN7android10TextOutputD0Ev;
- _ZN7android10TextOutputD1Ev;
- _ZN7android10TextOutputD2Ev;
- _ZN7android10zeroMemoryEPhm;
- _ZN7android11BnInterfaceINS_11IMemoryHeapEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_14IShellCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_15IResultReceiverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IClientCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os15IServiceManagerEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_2os16IServiceCallbackEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm21IPackageManagerNativeEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7content2pm22IPackageChangeObserverEE10onAsBinderEv;
- _ZN7android11BnInterfaceINS_7IMemoryEE10onAsBinderEv;
- _ZN7android11IMemoryHeap10descriptorE;
- _ZN7android11IMemoryHeap11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android11IMemoryHeap12default_implE;
- _ZN7android11IMemoryHeap14getDefaultImplEv;
- _ZN7android11IMemoryHeap14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android11IMemoryHeapC2Ev;
- _ZN7android11IMemoryHeapD0Ev;
- _ZN7android11IMemoryHeapD1Ev;
- _ZN7android11IMemoryHeapD2Ev;
- _ZN7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android12BnMemoryHeapC2Ev;
- _ZN7android12BnMemoryHeapD0Ev;
- _ZN7android12BnMemoryHeapD1Ev;
- _ZN7android12BnMemoryHeapD2Ev;
- _ZN7android12BpMemoryHeapC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android12BpMemoryHeapD0Ev;
- _ZN7android12BpMemoryHeapD1Ev;
- _ZN7android12BpMemoryHeapD2Ev;
- _ZN7android12gTextBuffersE;
- _ZN7android12MemoryDealer10deallocateEm;
- _ZN7android12MemoryDealer22getAllocationAlignmentEv;
- _ZN7android12MemoryDealer8allocateEm;
- _ZN7android12MemoryDealerC1EmPKcj;
- _ZN7android12MemoryDealerC2EmPKcj;
- _ZN7android12MemoryDealerD0Ev;
- _ZN7android12MemoryDealerD1Ev;
- _ZN7android12MemoryDealerD2Ev;
- _ZN7android12printHexDataEiPKvmmimbPFvPvPKcES2_;
- _ZN7android12ProcessState10selfOrNullEv;
- _ZN7android12ProcessState13expungeHandleEiPNS_7IBinderE;
- _ZN7android12ProcessState13getDriverNameEv;
- _ZN7android12ProcessState14initWithDriverEPKc;
- _ZN7android12ProcessState15startThreadPoolEv;
- _ZN7android12ProcessState16getContextObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android12ProcessState17spawnPooledThreadEb;
- _ZN7android12ProcessState18giveThreadPoolNameEv;
- _ZN7android12ProcessState18lookupHandleLockedEi;
- _ZN7android12ProcessState18setCallRestrictionENS0_15CallRestrictionE;
- _ZN7android12ProcessState19getKernelReferencesEmPm;
- _ZN7android12ProcessState20becomeContextManagerEv;
- _ZN7android12ProcessState20makeBinderThreadNameEv;
- _ZN7android12ProcessState23getStrongProxyForHandleEi;
- _ZN7android12ProcessState24getStrongRefCountForNodeERKNS_2spINS_8BpBinderEEE;
- _ZN7android12ProcessState25enableOnewaySpamDetectionEb;
- _ZN7android12ProcessState27setThreadPoolMaxThreadCountEm;
- _ZN7android12ProcessState4initEPKcb;
- _ZN7android12ProcessState4selfEv;
- _ZN7android12ProcessStateC1EPKc;
- _ZN7android12ProcessStateC2EPKc;
- _ZN7android12ProcessStateD0Ev;
- _ZN7android12ProcessStateD1Ev;
- _ZN7android12ProcessStateD2Ev;
- _ZN7android13printTypeCodeEjPFvPvPKcES0_;
- _ZN7android14IPCThreadState10freeBufferEPNS_6ParcelEPKhmPKym;
- _ZN7android14IPCThreadState10selfOrNullEv;
- _ZN7android14IPCThreadState11clearCallerEv;
- _ZN7android14IPCThreadState11stopProcessEb;
- _ZN7android14IPCThreadState12setupPollingEPi;
- _ZN7android14IPCThreadState13decWeakHandleEi;
- _ZN7android14IPCThreadState13expungeHandleEiPNS_7IBinderE;
- _ZN7android14IPCThreadState13flushCommandsEv;
- _ZN7android14IPCThreadState13flushIfNeededEv;
- _ZN7android14IPCThreadState13incWeakHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState14clearLastErrorEv;
- _ZN7android14IPCThreadState14executeCommandEi;
- _ZN7android14IPCThreadState14joinThreadPoolEb;
- _ZN7android14IPCThreadState14talkWithDriverEb;
- _ZN7android14IPCThreadState15decStrongHandleEi;
- _ZN7android14IPCThreadState15incStrongHandleEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi;
- _ZN7android14IPCThreadState16threadDestructorEPv;
- _ZN7android14IPCThreadState18setCallRestrictionENS_12ProcessState15CallRestrictionE;
- _ZN7android14IPCThreadState19setStrictModePolicyEi;
- _ZN7android14IPCThreadState19setTheContextObjectERKNS_2spINS_7BBinderEEE;
- _ZN7android14IPCThreadState20clearCallingIdentityEv;
- _ZN7android14IPCThreadState20getAndExecuteCommandEv;
- _ZN7android14IPCThreadState20getProcessFreezeInfoEiPbS1_;
- _ZN7android14IPCThreadState20handlePolledCommandsEv;
- _ZN7android14IPCThreadState20processPendingDerefsEv;
- _ZN7android14IPCThreadState20writeTransactionDataEijijRKNS_6ParcelEPi;
- _ZN7android14IPCThreadState22attemptIncStrongHandleEi;
- _ZN7android14IPCThreadState22clearCallingWorkSourceEv;
- _ZN7android14IPCThreadState22clearDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState22processPostWriteDerefsEv;
- _ZN7android14IPCThreadState22restoreCallingIdentityEl;
- _ZN7android14IPCThreadState23setCallingWorkSourceUidEj;
- _ZN7android14IPCThreadState24clearPropagateWorkSourceEv;
- _ZN7android14IPCThreadState24requestDeathNotificationEiPNS_8BpBinderE;
- _ZN7android14IPCThreadState24restoreCallingWorkSourceEl;
- _ZN7android14IPCThreadState25blockUntilThreadAvailableEv;
- _ZN7android14IPCThreadState27disableBackgroundSchedulingEb;
- _ZN7android14IPCThreadState28backgroundSchedulingDisabledEv;
- _ZN7android14IPCThreadState29setLastTransactionBinderFlagsEi;
- _ZN7android14IPCThreadState41setCallingWorkSourceUidWithoutPropagationEj;
- _ZN7android14IPCThreadState4selfEv;
- _ZN7android14IPCThreadState6freezeEibj;
- _ZN7android14IPCThreadState7processEv;
- _ZN7android14IPCThreadState8shutdownEv;
- _ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j;
- _ZN7android14IPCThreadState9sendReplyERKNS_6ParcelEj;
- _ZN7android14IPCThreadStateC1Ev;
- _ZN7android14IPCThreadStateC2Ev;
- _ZN7android14IPCThreadStateD1Ev;
- _ZN7android14IPCThreadStateD2Ev;
- _ZN7android14IShellCallback10descriptorE;
- _ZN7android14IShellCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android14IShellCallback12default_implE;
- _ZN7android14IShellCallback14getDefaultImplEv;
- _ZN7android14IShellCallback14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android14IShellCallbackC2Ev;
- _ZN7android14IShellCallbackD0Ev;
- _ZN7android14IShellCallbackD1Ev;
- _ZN7android14IShellCallbackD2Ev;
- _ZN7android14MemoryHeapBase4initEiPvmiPKc;
- _ZN7android14MemoryHeapBase5mapfdEibml;
- _ZN7android14MemoryHeapBase7disposeEv;
- _ZN7android14MemoryHeapBaseC1Eimjl;
- _ZN7android14MemoryHeapBaseC1EmjPKc;
- _ZN7android14MemoryHeapBaseC1EPKcmj;
- _ZN7android14MemoryHeapBaseC1Ev;
- _ZN7android14MemoryHeapBaseC2Eimjl;
- _ZN7android14MemoryHeapBaseC2EmjPKc;
- _ZN7android14MemoryHeapBaseC2EPKcmj;
- _ZN7android14MemoryHeapBaseC2Ev;
- _ZN7android14MemoryHeapBaseD0Ev;
- _ZN7android14MemoryHeapBaseD1Ev;
- _ZN7android14MemoryHeapBaseD2Ev;
- _ZN7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android15IResultReceiver10descriptorE;
- _ZN7android15IResultReceiver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android15IResultReceiver12default_implE;
- _ZN7android15IResultReceiver14getDefaultImplEv;
- _ZN7android15IResultReceiver14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android15IResultReceiverC2Ev;
- _ZN7android15IResultReceiverD0Ev;
- _ZN7android15IResultReceiverD1Ev;
- _ZN7android15IResultReceiverD2Ev;
- _ZN7android15IServiceManagerC2Ev;
- _ZN7android15IServiceManagerD0Ev;
- _ZN7android15IServiceManagerD1Ev;
- _ZN7android15IServiceManagerD2Ev;
- _ZN7android15stringForIndentEi;
- _ZN7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android18BufferedTextOutput10moveIndentEi;
- _ZN7android18BufferedTextOutput10pushBundleEv;
- _ZN7android18BufferedTextOutput5printEPKcm;
- _ZN7android18BufferedTextOutput9popBundleEv;
- _ZN7android18BufferedTextOutputC2Ej;
- _ZN7android18BufferedTextOutputD0Ev;
- _ZN7android18BufferedTextOutputD1Ev;
- _ZN7android18BufferedTextOutputD2Ev;
- _ZN7android18ServiceManagerShim10addServiceERKNS_8String16ERKNS_2spINS_7IBinderEEEbi;
- _ZN7android18ServiceManagerShim10isDeclaredERKNS_8String16E;
- _ZN7android18ServiceManagerShim12listServicesEi;
- _ZN7android18ServiceManagerShim14waitForServiceERKNS_8String16E;
- _ZN7android18ServiceManagerShim16updatableViaApexERKNS_8String16E;
- _ZN7android18ServiceManagerShim20getDeclaredInstancesERKNS_8String16E;
- _ZN7android18ServiceManagerShimC1ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18ServiceManagerShimC2ERKNS_2spINS_2os15IServiceManagerEEE;
- _ZN7android18the_context_objectE;
- _ZN7android21defaultServiceManagerEv;
- _ZN7android22SimpleBestFitAllocator10deallocateEm;
- _ZN7android22SimpleBestFitAllocator12kMemoryAlignE;
- _ZN7android22SimpleBestFitAllocator5allocEmj;
- _ZN7android22SimpleBestFitAllocator7deallocEm;
- _ZN7android22SimpleBestFitAllocator8allocateEmj;
- _ZN7android22SimpleBestFitAllocatorC1Em;
- _ZN7android22SimpleBestFitAllocatorC2Em;
- _ZN7android22SimpleBestFitAllocatorD1Ev;
- _ZN7android22SimpleBestFitAllocatorD2Ev;
- _ZN7android24setDefaultServiceManagerERKNS_2spINS_15IServiceManagerEEE;
- _ZN7android2os15IClientCallback10descriptorE;
- _ZN7android2os15IClientCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IClientCallback12default_implE;
- _ZN7android2os15IClientCallback14getDefaultImplEv;
- _ZN7android2os15IClientCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IClientCallbackC2Ev;
- _ZN7android2os15IClientCallbackD0Ev;
- _ZN7android2os15IClientCallbackD1Ev;
- _ZN7android2os15IClientCallbackD2Ev;
- _ZN7android2os15IServiceManager10descriptorE;
- _ZN7android2os15IServiceManager11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os15IServiceManager12default_implE;
- _ZN7android2os15IServiceManager14getDefaultImplEv;
- _ZN7android2os15IServiceManager14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os15IServiceManagerC2Ev;
- _ZN7android2os15IServiceManagerD0Ev;
- _ZN7android2os15IServiceManagerD1Ev;
- _ZN7android2os15IServiceManagerD2Ev;
- _ZN7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnClientCallbackC2Ev;
- _ZN7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os16BnServiceManagerC2Ev;
- _ZN7android2os16BpClientCallback9onClientsERKNS_2spINS_7IBinderEEEb;
- _ZN7android2os16BpClientCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpClientCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10addServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEEbi;
- _ZN7android2os16BpServiceManager10getServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager10isDeclaredERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPb;
- _ZN7android2os16BpServiceManager12checkServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager12listServicesEiPNSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEE;
- _ZN7android2os16BpServiceManager16updatableViaApexERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_8optionalIS8_EE;
- _ZN7android2os16BpServiceManager19getServiceDebugInfoEPNSt3__16vectorINS0_16ServiceDebugInfoENS2_9allocatorIS4_EEEE;
- _ZN7android2os16BpServiceManager20getDeclaredInstancesERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPNS2_6vectorIS8_NS6_IS8_EEEE;
- _ZN7android2os16BpServiceManager20tryUnregisterServiceERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManager22registerClientCallbackERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEERKNSB_INS0_15IClientCallbackEEE;
- _ZN7android2os16BpServiceManager24registerForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManager26unregisterForNotificationsERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS0_16IServiceCallbackEEE;
- _ZN7android2os16BpServiceManagerC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16BpServiceManagerC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback10descriptorE;
- _ZN7android2os16IServiceCallback11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android2os16IServiceCallback12default_implE;
- _ZN7android2os16IServiceCallback14getDefaultImplEv;
- _ZN7android2os16IServiceCallback14setDefaultImplENSt3__110unique_ptrIS1_NS2_14default_deleteIS1_EEEE;
- _ZN7android2os16IServiceCallbackC2Ev;
- _ZN7android2os16IServiceCallbackD0Ev;
- _ZN7android2os16IServiceCallbackD1Ev;
- _ZN7android2os16IServiceCallbackD2Ev;
- _ZN7android2os16ParcelableHolder14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os16ServiceDebugInfo14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZN7android2os17BnServiceCallbackC2Ev;
- _ZN7android2os17BpServiceCallback14onRegistrationERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17BpServiceCallbackC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android2os17PersistableBundle10putBooleanERKNS_8String16Eb;
- _ZN7android2os17PersistableBundle12putIntVectorERKNS_8String16ERKNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZN7android2os17PersistableBundle13putLongVectorERKNS_8String16ERKNSt3__16vectorIlNS5_9allocatorIlEEEE;
- _ZN7android2os17PersistableBundle14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os17PersistableBundle15putDoubleVectorERKNS_8String16ERKNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZN7android2os17PersistableBundle15putStringVectorERKNS_8String16ERKNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZN7android2os17PersistableBundle16putBooleanVectorERKNS_8String16ERKNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZN7android2os17PersistableBundle19readFromParcelInnerEPKNS_6ParcelEm;
- _ZN7android2os17PersistableBundle20putPersistableBundleERKNS_8String16ERKS1_;
- _ZN7android2os17PersistableBundle5eraseERKNS_8String16E;
- _ZN7android2os17PersistableBundle6putIntERKNS_8String16Ei;
- _ZN7android2os17PersistableBundle7putLongERKNS_8String16El;
- _ZN7android2os17PersistableBundle9putDoubleERKNS_8String16Ed;
- _ZN7android2os17PersistableBundle9putStringERKNS_8String16ES4_;
- _ZN7android2os20ParcelFileDescriptor14readFromParcelEPKNS_6ParcelE;
- _ZN7android2os20ParcelFileDescriptorC1ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC1Ev;
- _ZN7android2os20ParcelFileDescriptorC2ENS_4base14unique_fd_implINS2_13DefaultCloserEEE;
- _ZN7android2os20ParcelFileDescriptorC2Ev;
- _ZN7android2os20ParcelFileDescriptorD0Ev;
- _ZN7android2os20ParcelFileDescriptorD1Ev;
- _ZN7android2os20ParcelFileDescriptorD2Ev;
- _ZN7android4aerrE;
- _ZN7android4alogE;
- _ZN7android4aoutE;
- _ZN7android6binder20LazyServiceRegistrar10reRegisterEv;
- _ZN7android6binder20LazyServiceRegistrar11getInstanceEv;
- _ZN7android6binder20LazyServiceRegistrar12forcePersistEb;
- _ZN7android6binder20LazyServiceRegistrar13tryUnregisterEv;
- _ZN7android6binder20LazyServiceRegistrar15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEbi;
- _ZN7android6binder20LazyServiceRegistrar25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder20LazyServiceRegistrarC1Ev;
- _ZN7android6binder20LazyServiceRegistrarC2Ev;
- _ZN7android6binder6Status11fromStatusTEi;
- _ZN7android6binder6Status12setExceptionEiRKNS_7String8E;
- _ZN7android6binder6Status14readFromParcelERKNS_6ParcelE;
- _ZN7android6binder6Status14setFromStatusTEi;
- _ZN7android6binder6Status17exceptionToStringEi;
- _ZN7android6binder6Status17fromExceptionCodeEi;
- _ZN7android6binder6Status17fromExceptionCodeEiPKc;
- _ZN7android6binder6Status17fromExceptionCodeEiRKNS_7String8E;
- _ZN7android6binder6Status23setServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status24fromServiceSpecificErrorEi;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiPKc;
- _ZN7android6binder6Status24fromServiceSpecificErrorEiRKNS_7String8E;
- _ZN7android6binder6Status2okEv;
- _ZN7android6binder6StatusC1Eii;
- _ZN7android6binder6StatusC1EiiRKNS_7String8E;
- _ZN7android6binder6StatusC2Eii;
- _ZN7android6binder6StatusC2EiiRKNS_7String8E;
- _ZN7android6binder8internal21ClientCounterCallback10reRegisterEv;
- _ZN7android6binder8internal21ClientCounterCallback12forcePersistEb;
- _ZN7android6binder8internal21ClientCounterCallback13tryUnregisterEv;
- _ZN7android6binder8internal21ClientCounterCallback15registerServiceERKNS_2spINS_7IBinderEEERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEbi;
- _ZN7android6binder8internal21ClientCounterCallback25setActiveServicesCallbackERKNSt3__18functionIFbbEEE;
- _ZN7android6binder8internal21ClientCounterCallbackC1Ev;
- _ZN7android6binder8internal21ClientCounterCallbackC2Ev;
- _ZN7android6Parcel10appendFromEPKS0_mm;
- _ZN7android6Parcel10markForRpcERKNS_2spINS_10RpcSessionEEE;
- _ZN7android6Parcel10writeFloatEf;
- _ZN7android6Parcel10writeInt32Ei;
- _ZN7android6Parcel10writeInt64El;
- _ZN7android6Parcel11compareDataERKS0_;
- _ZN7android6Parcel11finishWriteEm;
- _ZN7android6Parcel11setDataSizeEm;
- _ZN7android6Parcel11writeDoubleEd;
- _ZN7android6Parcel11writeObjectERK18flat_binder_objectb;
- _ZN7android6Parcel11writeUint32Ej;
- _ZN7android6Parcel11writeUint64Em;
- _ZN7android6Parcel12pushAllowFdsEb;
- _ZN7android6Parcel12restartWriteEm;
- _ZN7android6Parcel12writeCStringEPKc;
- _ZN7android6Parcel12writeInplaceEm;
- _ZN7android6Parcel12writePointerEm;
- _ZN7android6Parcel12writeString8EPKcm;
- _ZN7android6Parcel12writeString8ERKNS_7String8E;
- _ZN7android6Parcel13continueWriteEm;
- _ZN7android6Parcel13flattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13markForBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel13writeString16EPKDsm;
- _ZN7android6Parcel13writeString16ERKNS_8String16E;
- _ZN7android6Parcel13writeString16ERKNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZN7android6Parcel13writeString16ERKNSt3__18optionalINS_8String16EEE;
- _ZN7android6Parcel13writeUnpaddedEPKvm;
- _ZN7android6Parcel14acquireObjectsEv;
- _ZN7android6Parcel14freeDataNoInitEv;
- _ZN7android6Parcel14releaseObjectsEv;
- _ZN7android6Parcel14writeByteArrayEmPKh;
- _ZN7android6Parcel15restoreAllowFdsEb;
- _ZN7android6Parcel15setDataCapacityEm;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZN7android6Parcel15writeBoolVectorERKNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZN7android6Parcel15writeByteVectorERKNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZN7android6Parcel15writeCharVectorERKNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZN7android6Parcel15writeInt32ArrayEmPKi;
- _ZN7android6Parcel15writeParcelableERKNS_10ParcelableE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZN7android6Parcel16writeFloatVectorERKNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZN7android6Parcel16writeInt32VectorERKNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__110unique_ptrINS1_6vectorIlNS1_9allocatorIlEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__16vectorIlNS1_9allocatorIlEEEE;
- _ZN7android6Parcel16writeInt64VectorERKNSt3__18optionalINS1_6vectorIlNS1_9allocatorIlEEEEEE;
- _ZN7android6Parcel16writeNoExceptionEv;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZN7android6Parcel16writeUtf8AsUtf16ERKNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZN7android6Parcel17writeDoubleVectorERKNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZN7android6Parcel17writeNativeHandleEPK13native_handle;
- _ZN7android6Parcel17writeStrongBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__110unique_ptrINS1_6vectorImNS1_9allocatorImEEEENS1_14default_deleteIS6_EEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__16vectorImNS1_9allocatorImEEEE;
- _ZN7android6Parcel17writeUint64VectorERKNSt3__18optionalINS1_6vectorImNS1_9allocatorImEEEEEE;
- _ZN7android6Parcel18getGlobalAllocSizeEv;
- _ZN7android6Parcel19finishFlattenBinderERKNS_2spINS_7IBinderEEE;
- _ZN7android6Parcel19getGlobalAllocCountEv;
- _ZN7android6Parcel19ipcSetDataReferenceEPKhmPKymPFvPS0_S2_mS4_mE;
- _ZN7android6Parcel19writeFileDescriptorEib;
- _ZN7android6Parcel19writeInterfaceTokenEPKDsm;
- _ZN7android6Parcel19writeInterfaceTokenERKNS_8String16E;
- _ZN7android6Parcel19writeString16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZN7android6Parcel19writeString16VectorERKNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZN7android6Parcel20closeFileDescriptorsEv;
- _ZN7android6Parcel22writeDupFileDescriptorEi;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZN7android6Parcel23writeStrongBinderVectorERKNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZN7android6Parcel25writeParcelFileDescriptorEib;
- _ZN7android6Parcel25writeUniqueFileDescriptorERKNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android6Parcel26writeRawNullableParcelableEPKNS_10ParcelableE;
- _ZN7android6Parcel27replaceCallingWorkSourceUidEj;
- _ZN7android6Parcel28writeDupParcelFileDescriptorEi;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZN7android6Parcel28writeUtf8VectorAsUtf16VectorERKNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZN7android6Parcel31writeUniqueFileDescriptorVectorERKNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZN7android6Parcel35writeDupImmutableBlobFileDescriptorEi;
- _ZN7android6Parcel4Blob4initEiPvmb;
- _ZN7android6Parcel4Blob5clearEv;
- _ZN7android6Parcel4Blob7releaseEv;
- _ZN7android6Parcel4BlobC1Ev;
- _ZN7android6Parcel4BlobC2Ev;
- _ZN7android6Parcel4BlobD1Ev;
- _ZN7android6Parcel4BlobD2Ev;
- _ZN7android6Parcel5writeEPKvm;
- _ZN7android6Parcel5writeERKNS0_26FlattenableHelperInterfaceE;
- _ZN7android6Parcel7setDataEPKhm;
- _ZN7android6Parcel8freeDataEv;
- _ZN7android6Parcel8growDataEm;
- _ZN7android6Parcel8setErrorEi;
- _ZN7android6Parcel9initStateEv;
- _ZN7android6Parcel9writeBlobEmbPNS0_12WritableBlobE;
- _ZN7android6Parcel9writeBoolEb;
- _ZN7android6Parcel9writeByteEa;
- _ZN7android6Parcel9writeCharEDs;
- _ZN7android6ParcelC1Ev;
- _ZN7android6ParcelC2Ev;
- _ZN7android6ParcelD1Ev;
- _ZN7android6ParcelD2Ev;
- _ZN7android7BBinder10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinder10pingBinderEv;
- _ZN7android7BBinder11getDebugPidEv;
- _ZN7android7BBinder11isInheritRtEv;
- _ZN7android7BBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android7BBinder11localBinderEv;
- _ZN7android7BBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android7BBinder12detachObjectEPKv;
- _ZN7android7BBinder12getExtensionEv;
- _ZN7android7BBinder12setExtensionERKNS_2spINS_7IBinderEEE;
- _ZN7android7BBinder12setInheritRtEb;
- _ZN7android7BBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android7BBinder15isRequestingSidEv;
- _ZN7android7BBinder16setRequestingSidEb;
- _ZN7android7BBinder17getOrCreateExtrasEv;
- _ZN7android7BBinder21getMinSchedulerPolicyEv;
- _ZN7android7BBinder21setMinSchedulerPolicyEii;
- _ZN7android7BBinder23getMinSchedulerPriorityEv;
- _ZN7android7BBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android7BBinderC1Ev;
- _ZN7android7BBinderC2Ev;
- _ZN7android7BBinderD0Ev;
- _ZN7android7BBinderD1Ev;
- _ZN7android7BBinderD2Ev;
- _ZN7android7content2pm18PackageChangeEvent14readFromParcelEPKNS_6ParcelE;
- _ZN7android7content2pm21IPackageManagerNative10descriptorE;
- _ZN7android7content2pm21IPackageManagerNative11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm21IPackageManagerNative12default_implE;
- _ZN7android7content2pm21IPackageManagerNative14getDefaultImplEv;
- _ZN7android7content2pm21IPackageManagerNative14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm21IPackageManagerNativeC2Ev;
- _ZN7android7content2pm21IPackageManagerNativeD0Ev;
- _ZN7android7content2pm21IPackageManagerNativeD1Ev;
- _ZN7android7content2pm21IPackageManagerNativeD2Ev;
- _ZN7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm22BnPackageManagerNativeC2Ev;
- _ZN7android7content2pm22BpPackageManagerNative14getAllPackagesEPNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative15getNamesForUidsERKNSt3__16vectorIiNS3_9allocatorIiEEEEPNS4_INS3_12basic_stringIcNS3_11char_traitsIcEENS5_IcEEEENS5_ISE_EEEE;
- _ZN7android7content2pm22BpPackageManagerNative16getLocationFlagsERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPi;
- _ZN7android7content2pm22BpPackageManagerNative16hasSystemFeatureERKNS_8String16EiPb;
- _ZN7android7content2pm22BpPackageManagerNative19isPackageDebuggableERKNS_8String16EPb;
- _ZN7android7content2pm22BpPackageManagerNative22getInstallerForPackageERKNS_8String16EPNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative24getVersionCodeForPackageERKNS_8String16EPl;
- _ZN7android7content2pm22BpPackageManagerNative27hasSha256SigningCertificateERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEERKNS3_6vectorIhNS7_IhEEEEPb;
- _ZN7android7content2pm22BpPackageManagerNative28getModuleMetadataPackageNameEPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29getTargetSdkVersionForPackageERKNS_8String16EPi;
- _ZN7android7content2pm22BpPackageManagerNative29isAudioPlaybackCaptureAllowedERKNSt3__16vectorINS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS8_ISA_EEEEPNS4_IbNS8_IbEEEE;
- _ZN7android7content2pm22BpPackageManagerNative29registerPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNative31unregisterPackageChangeObserverERKNS_2spINS1_22IPackageChangeObserverEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22BpPackageManagerNativeC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver10descriptorE;
- _ZN7android7content2pm22IPackageChangeObserver11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm22IPackageChangeObserver12default_implE;
- _ZN7android7content2pm22IPackageChangeObserver14getDefaultImplEv;
- _ZN7android7content2pm22IPackageChangeObserver14setDefaultImplENSt3__110unique_ptrIS2_NS3_14default_deleteIS2_EEEE;
- _ZN7android7content2pm22IPackageChangeObserverC2Ev;
- _ZN7android7content2pm22IPackageChangeObserverD0Ev;
- _ZN7android7content2pm22IPackageChangeObserverD1Ev;
- _ZN7android7content2pm22IPackageChangeObserverD2Ev;
- _ZN7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZN7android7content2pm23BnPackageChangeObserverC2Ev;
- _ZN7android7content2pm23BpPackageChangeObserver16onPackageChangedERKNS1_18PackageChangeEventE;
- _ZN7android7content2pm23BpPackageChangeObserverC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android7content2pm23BpPackageChangeObserverC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android7HexDumpC1EPKvmm;
- _ZN7android7HexDumpC2EPKvmm;
- _ZN7android7IBinder11getDebugPidEPi;
- _ZN7android7IBinder11localBinderEv;
- _ZN7android7IBinder12getExtensionEPNS_2spIS0_EE;
- _ZN7android7IBinder12remoteBinderEv;
- _ZN7android7IBinder12shellCommandERKNS_2spIS0_EEiiiRNS_6VectorINS_8String16EEERKNS1_INS_14IShellCallbackEEERKNS1_INS_15IResultReceiverEEE;
- _ZN7android7IBinder19queryLocalInterfaceERKNS_8String16E;
- _ZN7android7IBinderC2Ev;
- _ZN7android7IBinderD0Ev;
- _ZN7android7IBinderD1Ev;
- _ZN7android7IBinderD2Ev;
- _ZN7android7IMemory10descriptorE;
- _ZN7android7IMemory11asInterfaceERKNS_2spINS_7IBinderEEE;
- _ZN7android7IMemory12default_implE;
- _ZN7android7IMemory14getDefaultImplEv;
- _ZN7android7IMemory14setDefaultImplENSt3__110unique_ptrIS0_NS1_14default_deleteIS0_EEEE;
- _ZN7android7IMemoryC2Ev;
- _ZN7android7IMemoryD0Ev;
- _ZN7android7IMemoryD1Ev;
- _ZN7android7IMemoryD2Ev;
- _ZN7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BnMemoryC2Ev;
- _ZN7android8BnMemoryD0Ev;
- _ZN7android8BnMemoryD1Ev;
- _ZN7android8BnMemoryD2Ev;
- _ZN7android8BpBinder10onFirstRefEv;
- _ZN7android8BpBinder10pingBinderEv;
- _ZN7android8BpBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj;
- _ZN7android8BpBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E;
- _ZN7android8BpBinder12detachObjectEPKv;
- _ZN7android8BpBinder12remoteBinderEv;
- _ZN7android8BpBinder12sendObituaryEv;
- _ZN7android8BpBinder12sTrackingMapE;
- _ZN7android8BpBinder13getCountByUidERNS_6VectorIjEES3_;
- _ZN7android8BpBinder13ObjectManager4killEv;
- _ZN7android8BpBinder13ObjectManager6attachEPKvPvS4_PFvS3_S4_S4_E;
- _ZN7android8BpBinder13ObjectManager6detachEPKv;
- _ZN7android8BpBinder13ObjectManagerC1Ev;
- _ZN7android8BpBinder13ObjectManagerC2Ev;
- _ZN7android8BpBinder13ObjectManagerD1Ev;
- _ZN7android8BpBinder13ObjectManagerD2Ev;
- _ZN7android8BpBinder13sTrackingLockE;
- _ZN7android8BpBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_;
- _ZN7android8BpBinder14reportOneDeathERKNS0_8ObituaryE;
- _ZN7android8BpBinder14sLimitCallbackE;
- _ZN7android8BpBinder15onLastStrongRefEPKv;
- _ZN7android8BpBinder15sNumTrackedUidsE;
- _ZN7android8BpBinder16enableCountByUidEv;
- _ZN7android8BpBinder16setLimitCallbackEPFviE;
- _ZN7android8BpBinder17disableCountByUidEv;
- _ZN7android8BpBinder18sCountByUidEnabledE;
- _ZN7android8BpBinder19getBinderProxyCountEj;
- _ZN7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZN7android8BpBinder20setCountByUidEnabledEb;
- _ZN7android8BpBinder26sBinderProxyThrottleCreateE;
- _ZN7android8BpBinder29sBinderProxyCountLowWatermarkE;
- _ZN7android8BpBinder29setBinderProxyCountWatermarksEii;
- _ZN7android8BpBinder30sBinderProxyCountHighWatermarkE;
- _ZN7android8BpBinder4dumpEiRKNS_6VectorINS_8String16EEE;
- _ZN7android8BpBinder6createEi;
- _ZN7android8BpBinder6createERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j;
- _ZN7android8BpBinderC1EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC1EONS0_9RpcHandleE;
- _ZN7android8BpBinderC1EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderC2EONS0_12BinderHandleEi;
- _ZN7android8BpBinderC2EONS0_9RpcHandleE;
- _ZN7android8BpBinderC2EONSt3__17variantIJNS0_12BinderHandleENS0_9RpcHandleEEEE;
- _ZN7android8BpBinderD0Ev;
- _ZN7android8BpBinderD1Ev;
- _ZN7android8BpBinderD2Ev;
- _ZN7android8BpMemoryC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android8BpMemoryD0Ev;
- _ZN7android8BpMemoryD1Ev;
- _ZN7android8BpMemoryD2Ev;
- _ZN7android8internal9Stability11getCategoryEPNS_7IBinderE;
- _ZN7android8internal9Stability11levelStringENS1_5LevelE;
- _ZN7android8internal9Stability13getLocalLevelEv;
- _ZN7android8internal9Stability15isDeclaredLevelENS1_5LevelE;
- _ZN7android8internal9Stability17debugLogStabilityERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability19markCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability22tryMarkCompilationUnitEPNS_7IBinderE;
- _ZN7android8internal9Stability24requiresVintfDeclarationERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability25forceDowngradeToStabilityERKNS_2spINS_7IBinderEEENS1_5LevelE;
- _ZN7android8internal9Stability30forceDowngradeToLocalStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToSystemStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability31forceDowngradeToVendorStabilityERKNS_2spINS_7IBinderEEE;
- _ZN7android8internal9Stability5checkENS1_8CategoryENS1_5LevelE;
- _ZN7android8internal9Stability7setReprEPNS_7IBinderEij;
- _ZN7android8internal9Stability8Category11debugStringEv;
- _ZN7android8internal9Stability8markVndkEPNS_7IBinderE;
- _ZN7android8internal9Stability9markVintfEPNS_7IBinderE;
- _ZN7android8RpcState11CommandDataC1Em;
- _ZN7android8RpcState11CommandDataC2Em;
- _ZN7android8RpcState12countBindersEv;
- _ZN7android8RpcState12getSessionIdERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPi;
- _ZN7android8RpcState12waitForReplyERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPNS_6ParcelE;
- _ZN7android8RpcState13getMaxThreadsERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEEPm;
- _ZN7android8RpcState13getRootObjectERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState13sendDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressE;
- _ZN7android8RpcState15onBinderLeavingERKNS_2spINS_10RpcSessionEEERKNS1_INS_7IBinderEEEPNS_10RpcAddressE;
- _ZN7android8RpcState15processTransactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState16onBinderEnteringERKNS_2spINS_10RpcSessionEEERKNS_10RpcAddressE;
- _ZN7android8RpcState16processDecStrongERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState20getAndExecuteCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEE;
- _ZN7android8RpcState20processServerCommandERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEERKNS_13RpcWireHeaderE;
- _ZN7android8RpcState23processTransactInternalERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_2spINS_10RpcSessionEEENS0_11CommandDataE;
- _ZN7android8RpcState4dumpEv;
- _ZN7android8RpcState6rpcRecERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPvm;
- _ZN7android8RpcState7rpcSendERKNS_4base14unique_fd_implINS1_13DefaultCloserEEEPKcPKvm;
- _ZN7android8RpcState8transactERKNS_4base14unique_fd_implINS1_13DefaultCloserEEERKNS_10RpcAddressEjRKNS_6ParcelERKNS_2spINS_10RpcSessionEEEPSA_j;
- _ZN7android8RpcState9terminateEv;
- _ZN7android8RpcStateC1Ev;
- _ZN7android8RpcStateC2Ev;
- _ZN7android8RpcStateD1Ev;
- _ZN7android8RpcStateD2Ev;
- _ZN7android9BpRefBase10onFirstRefEv;
- _ZN7android9BpRefBase15onLastStrongRefEPKv;
- _ZN7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZN7android9BpRefBaseC1ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseC2ERKNS_2spINS_7IBinderEEE;
- _ZN7android9BpRefBaseD0Ev;
- _ZN7android9BpRefBaseD1Ev;
- _ZN7android9BpRefBaseD2Ev;
- _ZN7android9HeapCache10binderDiedERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCache10dump_heapsEv;
- _ZN7android9HeapCache8get_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9find_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2spINS_7IBinderEEE;
- _ZN7android9HeapCache9free_heapERKNS_2wpINS_7IBinderEEE;
- _ZN7android9HeapCacheC1Ev;
- _ZN7android9HeapCacheC2Ev;
- _ZN7android9HeapCacheD0Ev;
- _ZN7android9HeapCacheD1Ev;
- _ZN7android9HeapCacheD2Ev;
- _ZN7android9hexStringEPKvm;
- _ZN7android9RpcServer12listSessionsEv;
- _ZN7android9RpcServer13getMaxThreadsEv;
- _ZN7android9RpcServer13getRootObjectEv;
- _ZN7android9RpcServer13releaseServerEv;
- _ZN7android9RpcServer13setMaxThreadsEm;
- _ZN7android9RpcServer13setRootObjectERKNS_2spINS_7IBinderEEE;
- _ZN7android9RpcServer15setupInetServerEjPj;
- _ZN7android9RpcServer16setupVsockServerEj;
- _ZN7android9RpcServer17setRootObjectWeakERKNS_2wpINS_7IBinderEEE;
- _ZN7android9RpcServer17setupSocketServerERKNS_16RpcSocketAddressE;
- _ZN7android9RpcServer19establishConnectionEONS_2spIS0_EENS_4base14unique_fd_implINS4_13DefaultCloserEEE;
- _ZN7android9RpcServer19setupExternalServerENS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZN7android9RpcServer20onSessionTerminatingERKNS_2spINS_10RpcSessionEEE;
- _ZN7android9RpcServer21setupUnixDomainServerEPKc;
- _ZN7android9RpcServer24numUninitializedSessionsEv;
- _ZN7android9RpcServer4joinEv;
- _ZN7android9RpcServer4makeEv;
- _ZN7android9RpcServer61iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProductionEv;
- _ZN7android9RpcServer9acceptOneEv;
- _ZN7android9RpcServer9hasServerEv;
- _ZN7android9RpcServerC1Ev;
- _ZN7android9RpcServerC2Ev;
- _ZN7android9RpcServerD0Ev;
- _ZN7android9RpcServerD1Ev;
- _ZN7android9RpcServerD2Ev;
- _ZN7androidlsERNS_10TextOutputERKNS_7HexDumpE;
- _ZN7androidlsERNS_10TextOutputERKNS_8TypeCodeE;
- _ZN7androidlsIA15_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA24_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA2_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA34_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA3_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA43_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA4_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA5_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA8_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIA9_cEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIjEERNS_10TextOutputES2_RKT_;
- _ZN7androidlsImEERNS_10TextOutputES2_RKT_;
- _ZN7androidlsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEERNS_10TextOutputES9_RKT_;
- _ZN7androidlsIPcEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIPvEERNS_10TextOutputES3_RKT_;
- _ZN7androidlsIyEERNS_10TextOutputES2_RKT_;
- _ZNK7android10MemoryBase9getMemoryEPlPm;
- _ZNK7android10RpcAddress13writeToParcelEPNS_6ParcelE;
- _ZNK7android10RpcAddress15viewRawEmbeddedEv;
- _ZNK7android10RpcAddress6isZeroEv;
- _ZNK7android10RpcAddress8toStringEv;
- _ZNK7android10RpcAddressltERKS0_;
- _ZNK7android11IMemoryHeap22getInterfaceDescriptorEv;
- _ZNK7android12BpMemoryHeap12assertMappedEv;
- _ZNK7android12BpMemoryHeap18assertReallyMappedEv;
- _ZNK7android12BpMemoryHeap7getBaseEv;
- _ZNK7android12BpMemoryHeap7getSizeEv;
- _ZNK7android12BpMemoryHeap8getFlagsEv;
- _ZNK7android12BpMemoryHeap9getHeapIDEv;
- _ZNK7android12BpMemoryHeap9getOffsetEv;
- _ZNK7android12MemoryDealer4dumpEPKc;
- _ZNK7android12MemoryDealer4heapEv;
- _ZNK7android12MemoryDealer9allocatorEv;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_compareEPKvSA_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_destroyEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE12do_constructEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE15do_move_forwardEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE16do_move_backwardEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE7do_copyEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE8do_splatEPvPKvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_compareES3_S3_;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_destroyEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE12do_constructEPvm;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE15do_move_forwardEPvS3_m;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE16do_move_backwardEPvS3_m;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE7do_copyEPvS3_m;
- _ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE8do_splatEPvS3_m;
- _ZNK7android14IPCThreadState13getCallingPidEv;
- _ZNK7android14IPCThreadState13getCallingSidEv;
- _ZNK7android14IPCThreadState13getCallingUidEv;
- _ZNK7android14IPCThreadState18getCallRestrictionEv;
- _ZNK7android14IPCThreadState19getStrictModePolicyEv;
- _ZNK7android14IPCThreadState22getServingStackPointerEv;
- _ZNK7android14IPCThreadState23getCallingWorkSourceUidEv;
- _ZNK7android14IPCThreadState25shouldPropagateWorkSourceEv;
- _ZNK7android14IPCThreadState29getLastTransactionBinderFlagsEv;
- _ZNK7android14IShellCallback22getInterfaceDescriptorEv;
- _ZNK7android14MemoryHeapBase7getBaseEv;
- _ZNK7android14MemoryHeapBase7getSizeEv;
- _ZNK7android14MemoryHeapBase8getFlagsEv;
- _ZNK7android14MemoryHeapBase9getDeviceEv;
- _ZNK7android14MemoryHeapBase9getHeapIDEv;
- _ZNK7android14MemoryHeapBase9getOffsetEv;
- _ZNK7android15IResultReceiver22getInterfaceDescriptorEv;
- _ZNK7android15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android18BufferedTextOutput9getBufferEv;
- _ZNK7android18ServiceManagerShim10getServiceERKNS_8String16E;
- _ZNK7android18ServiceManagerShim12checkServiceERKNS_8String16E;
- _ZNK7android22SimpleBestFitAllocator4dumpEPKc;
- _ZNK7android22SimpleBestFitAllocator4dumpERNS_7String8EPKc;
- _ZNK7android22SimpleBestFitAllocator4sizeEv;
- _ZNK7android22SimpleBestFitAllocator6dump_lEPKc;
- _ZNK7android22SimpleBestFitAllocator6dump_lERNS_7String8EPKc;
- _ZNK7android2os15IClientCallback22getInterfaceDescriptorEv;
- _ZNK7android2os15IServiceManager22getInterfaceDescriptorEv;
- _ZNK7android2os16IServiceCallback22getInterfaceDescriptorEv;
- _ZNK7android2os16ParcelableHolder13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os16ServiceDebugInfo13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle10getBooleanERKNS_8String16EPb;
- _ZNK7android2os17PersistableBundle10getIntKeysEv;
- _ZNK7android2os17PersistableBundle11getLongKeysEv;
- _ZNK7android2os17PersistableBundle12getIntVectorERKNS_8String16EPNSt3__16vectorIiNS5_9allocatorIiEEEE;
- _ZNK7android2os17PersistableBundle13getDoubleKeysEv;
- _ZNK7android2os17PersistableBundle13getLongVectorERKNS_8String16EPNSt3__16vectorIlNS5_9allocatorIlEEEE;
- _ZNK7android2os17PersistableBundle13getStringKeysEv;
- _ZNK7android2os17PersistableBundle13writeToParcelEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle14getBooleanKeysEv;
- _ZNK7android2os17PersistableBundle15getDoubleVectorERKNS_8String16EPNSt3__16vectorIdNS5_9allocatorIdEEEE;
- _ZNK7android2os17PersistableBundle15getStringVectorERKNS_8String16EPNSt3__16vectorIS2_NS5_9allocatorIS2_EEEE;
- _ZNK7android2os17PersistableBundle16getBooleanVectorERKNS_8String16EPNSt3__16vectorIbNS5_9allocatorIbEEEE;
- _ZNK7android2os17PersistableBundle16getIntVectorKeysEv;
- _ZNK7android2os17PersistableBundle17getLongVectorKeysEv;
- _ZNK7android2os17PersistableBundle18writeToParcelInnerEPNS_6ParcelE;
- _ZNK7android2os17PersistableBundle19getDoubleVectorKeysEv;
- _ZNK7android2os17PersistableBundle19getStringVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getBooleanVectorKeysEv;
- _ZNK7android2os17PersistableBundle20getPersistableBundleERKNS_8String16EPS1_;
- _ZNK7android2os17PersistableBundle24getPersistableBundleKeysEv;
- _ZNK7android2os17PersistableBundle4sizeEv;
- _ZNK7android2os17PersistableBundle5emptyEv;
- _ZNK7android2os17PersistableBundle6getIntERKNS_8String16EPi;
- _ZNK7android2os17PersistableBundle7getLongERKNS_8String16EPl;
- _ZNK7android2os17PersistableBundle9getDoubleERKNS_8String16EPd;
- _ZNK7android2os17PersistableBundle9getStringERKNS_8String16EPS2_;
- _ZNK7android2os20ParcelFileDescriptor13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status13writeToParcelEPNS_6ParcelE;
- _ZNK7android6binder6Status9toString8Ev;
- _ZNK7android6Parcel10errorCheckEv;
- _ZNK7android6Parcel10ipcObjectsEv;
- _ZNK7android6Parcel10readDoubleEPd;
- _ZNK7android6Parcel10readDoubleEv;
- _ZNK7android6Parcel10readObjectEb;
- _ZNK7android6Parcel10readUint32EPj;
- _ZNK7android6Parcel10readUint32Ev;
- _ZNK7android6Parcel10readUint64EPm;
- _ZNK7android6Parcel10readUint64Ev;
- _ZNK7android6Parcel10scanForFdsEv;
- _ZNK7android6Parcel11ipcDataSizeEv;
- _ZNK7android6Parcel11readCStringEv;
- _ZNK7android6Parcel11readInplaceEm;
- _ZNK7android6Parcel11readPointerEPm;
- _ZNK7android6Parcel11readPointerEv;
- _ZNK7android6Parcel11readString8EPNS_7String8E;
- _ZNK7android6Parcel11readString8Ev;
- _ZNK7android6Parcel12dataCapacityEv;
- _ZNK7android6Parcel12dataPositionEv;
- _ZNK7android6Parcel12objectsCountEv;
- _ZNK7android6Parcel12readString16EPNS_8String16E;
- _ZNK7android6Parcel12readString16EPNSt3__110unique_ptrINS_8String16ENS1_14default_deleteIS3_EEEE;
- _ZNK7android6Parcel12readString16EPNSt3__18optionalINS_8String16EEE;
- _ZNK7android6Parcel12readString16Ev;
- _ZNK7android6Parcel13markSensitiveEv;
- _ZNK7android6Parcel14checkInterfaceEPNS_7IBinderE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__110unique_ptrINS1_6vectorIbNS1_9allocatorIbEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__16vectorIbNS1_9allocatorIbEEEE;
- _ZNK7android6Parcel14readBoolVectorEPNSt3__18optionalINS1_6vectorIbNS1_9allocatorIbEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIaNS1_9allocatorIaEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__110unique_ptrINS1_6vectorIhNS1_9allocatorIhEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIaNS1_9allocatorIaEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__16vectorIhNS1_9allocatorIhEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIaNS1_9allocatorIaEEEEEE;
- _ZNK7android6Parcel14readByteVectorEPNSt3__18optionalINS1_6vectorIhNS1_9allocatorIhEEEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__110unique_ptrINS1_6vectorIDsNS1_9allocatorIDsEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__16vectorIDsNS1_9allocatorIDsEEEE;
- _ZNK7android6Parcel14readCharVectorEPNSt3__18optionalINS1_6vectorIDsNS1_9allocatorIDsEEEEEE;
- _ZNK7android6Parcel14readParcelableEPNS_10ParcelableE;
- _ZNK7android6Parcel15ipcObjectsCountEv;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__110unique_ptrINS1_6vectorIfNS1_9allocatorIfEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__16vectorIfNS1_9allocatorIfEEEE;
- _ZNK7android6Parcel15readFloatVectorEPNSt3__18optionalINS1_6vectorIfNS1_9allocatorIfEEEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__110unique_ptrINS1_6vectorIiNS1_9allocatorIiEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__16vectorIiNS1_9allocatorIiEEEE;
- _ZNK7android6Parcel15readInt32VectorEPNSt3__18optionalINS1_6vectorIiNS1_9allocatorIiEEEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__110unique_ptrINS1_6vectorIlNS1_9allocatorIlEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__16vectorIlNS1_9allocatorIlEEEE;
- _ZNK7android6Parcel15readInt64VectorEPNSt3__18optionalINS1_6vectorIlNS1_9allocatorIlEEEEEE;
- _ZNK7android6Parcel15setDataPositionEm;
- _ZNK7android6Parcel15unflattenBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16enforceInterfaceEPKDsmPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16enforceInterfaceERKNS_8String16EPNS_14IPCThreadStateE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__110unique_ptrINS1_6vectorIdNS1_9allocatorIdEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__16vectorIdNS1_9allocatorIdEEEE;
- _ZNK7android6Parcel16readDoubleVectorEPNSt3__18optionalINS1_6vectorIdNS1_9allocatorIdEEEEEE;
- _ZNK7android6Parcel16readNativeHandleEv;
- _ZNK7android6Parcel16readStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel16readStrongBinderEv;
- _ZNK7android6Parcel16readStrongBinderINS_2os15IClientCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_2os16IServiceCallbackEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readStrongBinderINS_7content2pm22IPackageChangeObserverEEEiPNS_2spIT_EE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__110unique_ptrINS1_6vectorImNS1_9allocatorImEEEENS1_14default_deleteIS6_EEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__16vectorImNS1_9allocatorImEEEE;
- _ZNK7android6Parcel16readUint64VectorEPNSt3__18optionalINS1_6vectorImNS1_9allocatorImEEEEEE;
- _ZNK7android6Parcel16validateReadDataEm;
- _ZNK7android6Parcel17getBlobAshmemSizeEv;
- _ZNK7android6Parcel17getOpenAshmemSizeEv;
- _ZNK7android6Parcel17readExceptionCodeEv;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__110unique_ptrINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS8_EEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE;
- _ZNK7android6Parcel17readUtf8FromUtf16EPNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEE;
- _ZNK7android6Parcel18hasFileDescriptorsEv;
- _ZNK7android6Parcel18readFileDescriptorEv;
- _ZNK7android6Parcel18readString16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS_8String16ENS1_14default_deleteIS4_EEEENS1_9allocatorIS7_EEEENS5_ISA_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__16vectorINS_8String16ENS1_9allocatorIS3_EEEE;
- _ZNK7android6Parcel18readString16VectorEPNSt3__18optionalINS1_6vectorINS2_INS_8String16EEENS1_9allocatorIS5_EEEEEE;
- _ZNK7android6Parcel18readString8InplaceEPm;
- _ZNK7android6Parcel19readString16InplaceEPm;
- _ZNK7android6Parcel21finishUnflattenBinderERKNS_2spINS_7IBinderEEEPS3_;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__110unique_ptrINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEENS1_14default_deleteIS9_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__16vectorINS_2spINS_7IBinderEEENS1_9allocatorIS5_EEEE;
- _ZNK7android6Parcel22readStrongBinderVectorEPNSt3__18optionalINS1_6vectorINS_2spINS_7IBinderEEENS1_9allocatorIS6_EEEEEE;
- _ZNK7android6Parcel24readCallingWorkSourceUidEv;
- _ZNK7android6Parcel24readNullableStrongBinderEPNS_2spINS_7IBinderEEE;
- _ZNK7android6Parcel24readParcelFileDescriptorEv;
- _ZNK7android6Parcel24readUniqueFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__110unique_ptrINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_14default_deleteIS9_EEEENS7_ISC_EEEENSA_ISE_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__16vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE;
- _ZNK7android6Parcel29readUtf8VectorFromUtf16VectorEPNSt3__18optionalINS1_6vectorINS2_INS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS7_ISA_EEEEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__110unique_ptrINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEENS1_14default_deleteISA_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__16vectorINS_4base14unique_fd_implINS3_13DefaultCloserEEENS1_9allocatorIS6_EEEE;
- _ZNK7android6Parcel30readUniqueFileDescriptorVectorEPNSt3__18optionalINS1_6vectorINS_4base14unique_fd_implINS4_13DefaultCloserEEENS1_9allocatorIS7_EEEEEE;
- _ZNK7android6Parcel30readUniqueParcelFileDescriptorEPNS_4base14unique_fd_implINS1_13DefaultCloserEEE;
- _ZNK7android6Parcel37updateWorkSourceRequestHeaderPositionEv;
- _ZNK7android6Parcel4dataEv;
- _ZNK7android6Parcel4readEPvm;
- _ZNK7android6Parcel4readERNS0_26FlattenableHelperInterfaceE;
- _ZNK7android6Parcel5printERNS_10TextOutputEj;
- _ZNK7android6Parcel7ipcDataEv;
- _ZNK7android6Parcel8allowFdsEv;
- _ZNK7android6Parcel8dataSizeEv;
- _ZNK7android6Parcel8isForRpcEv;
- _ZNK7android6Parcel8readBlobEmPNS0_12ReadableBlobE;
- _ZNK7android6Parcel8readBoolEPb;
- _ZNK7android6Parcel8readBoolEv;
- _ZNK7android6Parcel8readByteEPa;
- _ZNK7android6Parcel8readByteEv;
- _ZNK7android6Parcel8readCharEPDs;
- _ZNK7android6Parcel8readCharEv;
- _ZNK7android6Parcel9dataAvailEv;
- _ZNK7android6Parcel9readFloatEPf;
- _ZNK7android6Parcel9readFloatEv;
- _ZNK7android6Parcel9readInt32EPi;
- _ZNK7android6Parcel9readInt32Ev;
- _ZNK7android6Parcel9readInt64EPl;
- _ZNK7android6Parcel9readInt64Ev;
- _ZNK7android6VectorIiE10do_destroyEPvm;
- _ZNK7android6VectorIiE12do_constructEPvm;
- _ZNK7android6VectorIiE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIiE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIiE7do_copyEPvPKvm;
- _ZNK7android6VectorIiE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE10do_destroyEPvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE12do_constructEPvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_12ProcessState12handle_entryEE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE10do_destroyEPvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE12do_constructEPvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE10do_destroyEPvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE12do_constructEPvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_8BpBinder8ObituaryEE8do_splatEPvPKvm;
- _ZNK7android6VectorINS_8String16EE10do_destroyEPvm;
- _ZNK7android6VectorINS_8String16EE12do_constructEPvm;
- _ZNK7android6VectorINS_8String16EE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorINS_8String16EE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorINS_8String16EE7do_copyEPvPKvm;
- _ZNK7android6VectorINS_8String16EE8do_splatEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE10do_destroyEPvm;
- _ZNK7android6VectorIPNS_7BBinderEE12do_constructEPvm;
- _ZNK7android6VectorIPNS_7BBinderEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE7do_copyEPvPKvm;
- _ZNK7android6VectorIPNS_7BBinderEE8do_splatEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE10do_destroyEPvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE12do_constructEPvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE7do_copyEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBase12weakref_typeEE8do_splatEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE10do_destroyEPvm;
- _ZNK7android6VectorIPNS_7RefBaseEE12do_constructEPvm;
- _ZNK7android6VectorIPNS_7RefBaseEE15do_move_forwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE16do_move_backwardEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE7do_copyEPvPKvm;
- _ZNK7android6VectorIPNS_7RefBaseEE8do_splatEPvPKvm;
- _ZNK7android7BBinder10findObjectEPKv;
- _ZNK7android7BBinder13isBinderAliveEv;
- _ZNK7android7BBinder22getInterfaceDescriptorEv;
- _ZNK7android7content2pm18PackageChangeEvent13writeToParcelEPNS_6ParcelE;
- _ZNK7android7content2pm21IPackageManagerNative22getInterfaceDescriptorEv;
- _ZNK7android7content2pm22IPackageChangeObserver22getInterfaceDescriptorEv;
- _ZNK7android7IBinder13checkSubclassEPKv;
- _ZNK7android7IMemory11fastPointerERKNS_2spINS_7IBinderEEEl;
- _ZNK7android7IMemory15unsecurePointerEv;
- _ZNK7android7IMemory22getInterfaceDescriptorEv;
- _ZNK7android7IMemory4sizeEv;
- _ZNK7android7IMemory6offsetEv;
- _ZNK7android7IMemory7pointerEv;
- _ZNK7android8BpBinder10findObjectEPKv;
- _ZNK7android8BpBinder10rpcAddressEv;
- _ZNK7android8BpBinder10rpcSessionEv;
- _ZNK7android8BpBinder11isRpcBinderEv;
- _ZNK7android8BpBinder12binderHandleEv;
- _ZNK7android8BpBinder13isBinderAliveEv;
- _ZNK7android8BpBinder13ObjectManager4findEPKv;
- _ZNK7android8BpBinder18isDescriptorCachedEv;
- _ZNK7android8BpBinder22getInterfaceDescriptorEv;
- _ZNK7android8BpMemory9getMemoryEPlPm;
- _ZTCN7android10AllocationE0_NS_10IInterfaceE;
- _ZTCN7android10AllocationE0_NS_10MemoryBaseE;
- _ZTCN7android10AllocationE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10AllocationE0_NS_7IMemoryE;
- _ZTCN7android10AllocationE0_NS_8BnMemoryE;
- _ZTCN7android10AllocationE8_NS_7BBinderE;
- _ZTCN7android10AllocationE8_NS_7IBinderE;
- _ZTCN7android10MemoryBaseE0_NS_10IInterfaceE;
- _ZTCN7android10MemoryBaseE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android10MemoryBaseE0_NS_7IMemoryE;
- _ZTCN7android10MemoryBaseE0_NS_8BnMemoryE;
- _ZTCN7android10MemoryBaseE8_NS_7BBinderE;
- _ZTCN7android10MemoryBaseE8_NS_7IBinderE;
- _ZTCN7android10PoolThreadE0_NS_6ThreadE;
- _ZTCN7android11IMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BnMemoryHeapE0_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BnMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BnMemoryHeapE8_NS_7BBinderE;
- _ZTCN7android12BnMemoryHeapE8_NS_7IBinderE;
- _ZTCN7android12BpMemoryHeapE0_NS_10IInterfaceE;
- _ZTCN7android12BpMemoryHeapE0_NS_11BpInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android12BpMemoryHeapE0_NS_11IMemoryHeapE;
- _ZTCN7android12BpMemoryHeapE8_NS_9BpRefBaseE;
- _ZTCN7android14IShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE64_NS_10IInterfaceE;
- _ZTCN7android14MemoryHeapBaseE64_NS_11BnInterfaceINS_11IMemoryHeapEEE;
- _ZTCN7android14MemoryHeapBaseE64_NS_11IMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE64_NS_12BnMemoryHeapE;
- _ZTCN7android14MemoryHeapBaseE72_NS_7BBinderE;
- _ZTCN7android14MemoryHeapBaseE72_NS_7IBinderE;
- _ZTCN7android15BnShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BnShellCallbackE0_NS_11BnInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BnShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BnShellCallbackE8_NS_7BBinderE;
- _ZTCN7android15BnShellCallbackE8_NS_7IBinderE;
- _ZTCN7android15BpShellCallbackE0_NS_10IInterfaceE;
- _ZTCN7android15BpShellCallbackE0_NS_11BpInterfaceINS_14IShellCallbackEEE;
- _ZTCN7android15BpShellCallbackE0_NS_14IShellCallbackE;
- _ZTCN7android15BpShellCallbackE8_NS_9BpRefBaseE;
- _ZTCN7android15IResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BnResultReceiverE0_NS_11BnInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BnResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BnResultReceiverE8_NS_7BBinderE;
- _ZTCN7android16BnResultReceiverE8_NS_7IBinderE;
- _ZTCN7android16BpResultReceiverE0_NS_10IInterfaceE;
- _ZTCN7android16BpResultReceiverE0_NS_11BpInterfaceINS_15IResultReceiverEEE;
- _ZTCN7android16BpResultReceiverE0_NS_15IResultReceiverE;
- _ZTCN7android16BpResultReceiverE8_NS_9BpRefBaseE;
- _ZTCN7android18ServiceManagerShimE0_NS_10IInterfaceE;
- _ZTCN7android18ServiceManagerShimE0_NS_15IServiceManagerE;
- _ZTCN7android2os15IClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os15IServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BnClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnClientCallbackE0_NS_11BnInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BnClientCallbackE8_NS_7BBinderE;
- _ZTCN7android2os16BnClientCallbackE8_NS_7IBinderE;
- _ZTCN7android2os16BnServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BnServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BnServiceManagerE0_NS_11BnInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BnServiceManagerE8_NS_7BBinderE;
- _ZTCN7android2os16BnServiceManagerE8_NS_7IBinderE;
- _ZTCN7android2os16BpClientCallbackE0_NS0_15IClientCallbackE;
- _ZTCN7android2os16BpClientCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpClientCallbackE0_NS_11BpInterfaceINS0_15IClientCallbackEEE;
- _ZTCN7android2os16BpClientCallbackE8_NS_9BpRefBaseE;
- _ZTCN7android2os16BpServiceManagerE0_NS0_15IServiceManagerE;
- _ZTCN7android2os16BpServiceManagerE0_NS_10IInterfaceE;
- _ZTCN7android2os16BpServiceManagerE0_NS_11BpInterfaceINS0_15IServiceManagerEEE;
- _ZTCN7android2os16BpServiceManagerE8_NS_9BpRefBaseE;
- _ZTCN7android2os16IServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BnServiceCallbackE0_NS_11BnInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BnServiceCallbackE8_NS_7BBinderE;
- _ZTCN7android2os17BnServiceCallbackE8_NS_7IBinderE;
- _ZTCN7android2os17BpServiceCallbackE0_NS0_16IServiceCallbackE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_10IInterfaceE;
- _ZTCN7android2os17BpServiceCallbackE0_NS_11BpInterfaceINS0_16IServiceCallbackEEE;
- _ZTCN7android2os17BpServiceCallbackE8_NS_9BpRefBaseE;
- _ZTCN7android7BBinderE0_NS_7IBinderE;
- _ZTCN7android7content2pm21IPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS_11BnInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE8_NS_7BBinderE;
- _ZTCN7android7content2pm22BnPackageManagerNativeE8_NS_7IBinderE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS_11BpInterfaceINS1_21IPackageManagerNativeEEE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE0_NS1_21IPackageManagerNativeE;
- _ZTCN7android7content2pm22BpPackageManagerNativeE8_NS_9BpRefBaseE;
- _ZTCN7android7content2pm22IPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS_11BnInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE8_NS_7BBinderE;
- _ZTCN7android7content2pm23BnPackageChangeObserverE8_NS_7IBinderE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_10IInterfaceE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS_11BpInterfaceINS1_22IPackageChangeObserverEEE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE0_NS1_22IPackageChangeObserverE;
- _ZTCN7android7content2pm23BpPackageChangeObserverE8_NS_9BpRefBaseE;
- _ZTCN7android7IMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BnMemoryE0_NS_11BnInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BnMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BnMemoryE8_NS_7BBinderE;
- _ZTCN7android8BnMemoryE8_NS_7IBinderE;
- _ZTCN7android8BpBinderE0_NS_7IBinderE;
- _ZTCN7android8BpMemoryE0_NS_10IInterfaceE;
- _ZTCN7android8BpMemoryE0_NS_11BpInterfaceINS_7IMemoryEEE;
- _ZTCN7android8BpMemoryE0_NS_7IMemoryE;
- _ZTCN7android8BpMemoryE8_NS_9BpRefBaseE;
- _ZTCN7android9HeapCacheE0_NS_7IBinder14DeathRecipientE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_13basic_istreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE0_NS_14basic_iostreamIcS2_EE;
- _ZTCNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE16_NS_13basic_ostreamIcS2_EE;
- _ZThn8_N7android10AllocationD0Ev;
- _ZThn8_N7android10AllocationD1Ev;
- _ZThn8_N7android10MemoryBaseD0Ev;
- _ZThn8_N7android10MemoryBaseD1Ev;
- _ZThn8_N7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android12BnMemoryHeapD0Ev;
- _ZThn8_N7android12BnMemoryHeapD1Ev;
- _ZThn8_N7android12BpMemoryHeapD0Ev;
- _ZThn8_N7android12BpMemoryHeapD1Ev;
- _ZThn8_N7android15BnShellCallback10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android16BnResultReceiver10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android2os16BnClientCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn8_N7android2os16BnServiceManager10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn8_N7android2os17BnServiceCallback10onTransactEjRKNS_6ParcelEPS2_j;
- _ZThn8_N7android7content2pm22BnPackageManagerNative10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn8_N7android7content2pm23BnPackageChangeObserver10onTransactEjRKNS_6ParcelEPS3_j;
- _ZThn8_N7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j;
- _ZThn8_N7android8BnMemoryD0Ev;
- _ZThn8_N7android8BnMemoryD1Ev;
- _ZThn8_N7android8BpMemoryD0Ev;
- _ZThn8_N7android8BpMemoryD1Ev;
- _ZTTN7android10AllocationE;
- _ZTTN7android10IInterfaceE;
- _ZTTN7android10MemoryBaseE;
- _ZTTN7android10PoolThreadE;
- _ZTTN7android10RpcSessionE;
- _ZTTN7android11IMemoryHeapE;
- _ZTTN7android12BnMemoryHeapE;
- _ZTTN7android12BpMemoryHeapE;
- _ZTTN7android12ProcessStateE;
- _ZTTN7android14IShellCallbackE;
- _ZTTN7android14MemoryHeapBaseE;
- _ZTTN7android15BnShellCallbackE;
- _ZTTN7android15BpShellCallbackE;
- _ZTTN7android15IResultReceiverE;
- _ZTTN7android15IServiceManagerE;
- _ZTTN7android16BnResultReceiverE;
- _ZTTN7android16BpResultReceiverE;
- _ZTTN7android18ServiceManagerShimE;
- _ZTTN7android2os15IClientCallbackE;
- _ZTTN7android2os15IServiceManagerE;
- _ZTTN7android2os16BnClientCallbackE;
- _ZTTN7android2os16BnServiceManagerE;
- _ZTTN7android2os16BpClientCallbackE;
- _ZTTN7android2os16BpServiceManagerE;
- _ZTTN7android2os16IServiceCallbackE;
- _ZTTN7android2os17BnServiceCallbackE;
- _ZTTN7android2os17BpServiceCallbackE;
- _ZTTN7android7BBinderE;
- _ZTTN7android7content2pm21IPackageManagerNativeE;
- _ZTTN7android7content2pm22BnPackageManagerNativeE;
- _ZTTN7android7content2pm22BpPackageManagerNativeE;
- _ZTTN7android7content2pm22IPackageChangeObserverE;
- _ZTTN7android7content2pm23BnPackageChangeObserverE;
- _ZTTN7android7content2pm23BpPackageChangeObserverE;
- _ZTTN7android7IBinderE;
- _ZTTN7android7IMemoryE;
- _ZTTN7android8BnMemoryE;
- _ZTTN7android8BpBinderE;
- _ZTTN7android8BpMemoryE;
- _ZTTN7android9BpRefBaseE;
- _ZTTN7android9HeapCacheE;
- _ZTTN7android9RpcServerE;
- _ZTTNSt3__118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE;
- _ZTv0_n24_N7android10AllocationD0Ev;
- _ZTv0_n24_N7android10AllocationD1Ev;
- _ZTv0_n24_N7android10IInterfaceD0Ev;
- _ZTv0_n24_N7android10IInterfaceD1Ev;
- _ZTv0_n24_N7android10MemoryBaseD0Ev;
- _ZTv0_n24_N7android10MemoryBaseD1Ev;
- _ZTv0_n24_N7android10RpcSessionD0Ev;
- _ZTv0_n24_N7android10RpcSessionD1Ev;
- _ZTv0_n24_N7android11IMemoryHeapD0Ev;
- _ZTv0_n24_N7android11IMemoryHeapD1Ev;
- _ZTv0_n24_N7android12BnMemoryHeapD0Ev;
- _ZTv0_n24_N7android12BnMemoryHeapD1Ev;
- _ZTv0_n24_N7android12BpMemoryHeapD0Ev;
- _ZTv0_n24_N7android12BpMemoryHeapD1Ev;
- _ZTv0_n24_N7android12ProcessStateD0Ev;
- _ZTv0_n24_N7android12ProcessStateD1Ev;
- _ZTv0_n24_N7android14IShellCallbackD0Ev;
- _ZTv0_n24_N7android14IShellCallbackD1Ev;
- _ZTv0_n24_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n24_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n24_N7android15IResultReceiverD0Ev;
- _ZTv0_n24_N7android15IResultReceiverD1Ev;
- _ZTv0_n24_N7android15IServiceManagerD0Ev;
- _ZTv0_n24_N7android15IServiceManagerD1Ev;
- _ZTv0_n24_N7android2os15IClientCallbackD0Ev;
- _ZTv0_n24_N7android2os15IClientCallbackD1Ev;
- _ZTv0_n24_N7android2os15IServiceManagerD0Ev;
- _ZTv0_n24_N7android2os15IServiceManagerD1Ev;
- _ZTv0_n24_N7android2os16IServiceCallbackD0Ev;
- _ZTv0_n24_N7android2os16IServiceCallbackD1Ev;
- _ZTv0_n24_N7android7BBinderD0Ev;
- _ZTv0_n24_N7android7BBinderD1Ev;
- _ZTv0_n24_N7android7content2pm21IPackageManagerNativeD0Ev;
- _ZTv0_n24_N7android7content2pm21IPackageManagerNativeD1Ev;
- _ZTv0_n24_N7android7content2pm22IPackageChangeObserverD0Ev;
- _ZTv0_n24_N7android7content2pm22IPackageChangeObserverD1Ev;
- _ZTv0_n24_N7android7IBinderD0Ev;
- _ZTv0_n24_N7android7IBinderD1Ev;
- _ZTv0_n24_N7android7IMemoryD0Ev;
- _ZTv0_n24_N7android7IMemoryD1Ev;
- _ZTv0_n24_N7android8BnMemoryD0Ev;
- _ZTv0_n24_N7android8BnMemoryD1Ev;
- _ZTv0_n24_N7android8BpBinderD0Ev;
- _ZTv0_n24_N7android8BpBinderD1Ev;
- _ZTv0_n24_N7android8BpMemoryD0Ev;
- _ZTv0_n24_N7android8BpMemoryD1Ev;
- _ZTv0_n24_N7android9BpRefBaseD0Ev;
- _ZTv0_n24_N7android9BpRefBaseD1Ev;
- _ZTv0_n24_N7android9HeapCacheD0Ev;
- _ZTv0_n24_N7android9HeapCacheD1Ev;
- _ZTv0_n24_N7android9RpcServerD0Ev;
- _ZTv0_n24_N7android9RpcServerD1Ev;
- _ZTv0_n32_N7android14MemoryHeapBaseD0Ev;
- _ZTv0_n32_N7android14MemoryHeapBaseD1Ev;
- _ZTv0_n32_N7android8BpBinder10onFirstRefEv;
- _ZTv0_n32_N7android9BpRefBase10onFirstRefEv;
- _ZTv0_n40_N7android8BpBinder15onLastStrongRefEPKv;
- _ZTv0_n40_N7android9BpRefBase15onLastStrongRefEPKv;
- _ZTv0_n48_N7android8BpBinder20onIncStrongAttemptedEjPKv;
- _ZTv0_n48_N7android9BpRefBase20onIncStrongAttemptedEjPKv;
- _ZTv0_n56_NK7android14MemoryHeapBase9getHeapIDEv;
- _ZTv0_n64_NK7android14MemoryHeapBase7getBaseEv;
- _ZTv0_n72_NK7android14MemoryHeapBase7getSizeEv;
- _ZTv0_n80_NK7android14MemoryHeapBase8getFlagsEv;
- _ZTv0_n88_NK7android14MemoryHeapBase9getOffsetEv;
- _ZTVN7android10AllocationE;
- _ZTVN7android10IInterfaceE;
- _ZTVN7android10MemoryBaseE;
- _ZTVN7android10PoolThreadE;
- _ZTVN7android10RpcSession13RpcConnectionE;
- _ZTVN7android10RpcSessionE;
- _ZTVN7android10TextOutputE;
- _ZTVN7android11IMemoryHeapE;
- _ZTVN7android12BnMemoryHeapE;
- _ZTVN7android12BpMemoryHeapE;
- _ZTVN7android12FdTextOutputE;
- _ZTVN7android12MemoryDealerE;
- _ZTVN7android12ProcessStateE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEE;
- _ZTVN7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEEE;
- _ZTVN7android13LogTextOutputE;
- _ZTVN7android14IShellCallbackE;
- _ZTVN7android14MemoryHeapBaseE;
- _ZTVN7android15BnShellCallbackE;
- _ZTVN7android15BpShellCallbackE;
- _ZTVN7android15IResultReceiverE;
- _ZTVN7android15IServiceManagerE;
- _ZTVN7android16BnResultReceiverE;
- _ZTVN7android16BpResultReceiverE;
- _ZTVN7android17InetSocketAddressE;
- _ZTVN7android17UnixSocketAddressE;
- _ZTVN7android18BufferedTextOutput11BufferStateE;
- _ZTVN7android18BufferedTextOutputE;
- _ZTVN7android18ServiceManagerShimE;
- _ZTVN7android18VsockSocketAddressE;
- _ZTVN7android2os15IClientCallbackE;
- _ZTVN7android2os15IServiceManagerE;
- _ZTVN7android2os16BnClientCallbackE;
- _ZTVN7android2os16BnServiceManagerE;
- _ZTVN7android2os16BpClientCallbackE;
- _ZTVN7android2os16BpServiceManagerE;
- _ZTVN7android2os16IServiceCallbackE;
- _ZTVN7android2os16ParcelableHolderE;
- _ZTVN7android2os16ServiceDebugInfoE;
- _ZTVN7android2os17BnServiceCallbackE;
- _ZTVN7android2os17BpServiceCallbackE;
- _ZTVN7android2os17PersistableBundleE;
- _ZTVN7android2os20ParcelFileDescriptorE;
- _ZTVN7android6VectorIiEE;
- _ZTVN7android6VectorINS_12ProcessState12handle_entryEEE;
- _ZTVN7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEEE;
- _ZTVN7android6VectorINS_8BpBinder8ObituaryEEE;
- _ZTVN7android6VectorINS_8String16EEE;
- _ZTVN7android6VectorIPNS_7BBinderEEE;
- _ZTVN7android6VectorIPNS_7RefBase12weakref_typeEEE;
- _ZTVN7android6VectorIPNS_7RefBaseEEE;
- _ZTVN7android7BBinderE;
- _ZTVN7android7content2pm18PackageChangeEventE;
- _ZTVN7android7content2pm21IPackageManagerNativeE;
- _ZTVN7android7content2pm22BnPackageManagerNativeE;
- _ZTVN7android7content2pm22BpPackageManagerNativeE;
- _ZTVN7android7content2pm22IPackageChangeObserverE;
- _ZTVN7android7content2pm23BnPackageChangeObserverE;
- _ZTVN7android7content2pm23BpPackageChangeObserverE;
- _ZTVN7android7IBinderE;
- _ZTVN7android7IMemoryE;
- _ZTVN7android8BnMemoryE;
- _ZTVN7android8BpBinderE;
- _ZTVN7android8BpMemoryE;
- _ZTVN7android9BpRefBaseE;
- _ZTVN7android9HeapCacheE;
- _ZTVN7android9RpcServerE;
- _ZTvn8_n32_N7android14MemoryHeapBaseD0Ev;
- _ZTvn8_n32_N7android14MemoryHeapBaseD1Ev;
- local:
- *;
-};
diff --git a/libs/binder/libbinder.map b/libs/binder/libbinder.map
new file mode 100644
index 0000000..9ca14bc
--- /dev/null
+++ b/libs/binder/libbinder.map
@@ -0,0 +1,5 @@
+# b/190148312: Populate with correct list of ABI symbols
+LIBBINDER {
+ global:
+ *;
+};
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
new file mode 100644
index 0000000..bf2b25b
--- /dev/null
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <android/binder_libbinder.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <linux/vm_sockets.h>
+
+using android::OK;
+using android::RpcServer;
+using android::RpcSession;
+using android::status_t;
+using android::statusToString;
+using android::base::unique_fd;
+
+extern "C" {
+
+bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
+ void* factoryContext, unsigned int port) {
+ auto server = RpcServer::make();
+ if (status_t status = server->setupVsockServer(port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock server with port " << port
+ << " error: " << statusToString(status).c_str();
+ return false;
+ }
+ server->setPerSessionRootObject([=](const sockaddr* addr, socklen_t addrlen) {
+ LOG_ALWAYS_FATAL_IF(addr->sa_family != AF_VSOCK, "address is not a vsock");
+ LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
+ const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+ return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
+ });
+
+ server->join();
+
+ // Shutdown any open sessions since server failed.
+ (void)server->shutdown();
+ return true;
+}
+
+bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
+ void* param) {
+ auto server = RpcServer::make();
+ if (status_t status = server->setupVsockServer(port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock server with port " << port
+ << " error: " << statusToString(status).c_str();
+ return false;
+ }
+ server->setRootObject(AIBinder_toPlatformBinder(service));
+
+ if (readyCallback) readyCallback(param);
+ server->join();
+
+ // Shutdown any open sessions since server failed.
+ (void)server->shutdown();
+ return true;
+}
+
+bool RunRpcServer(AIBinder* service, unsigned int port) {
+ return RunRpcServerCallback(service, port, nullptr, nullptr);
+}
+
+AIBinder* RpcClient(unsigned int cid, unsigned int port) {
+ auto session = RpcSession::make();
+ if (status_t status = session->setupVsockClient(cid, port); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
+ << " error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
+AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
+ auto session = RpcSession::make();
+ auto request = [=] { return unique_fd{requestFd(param)}; };
+ if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
+ LOG(ERROR) << "Failed to set up vsock client. error: " << statusToString(status).c_str();
+ return nullptr;
+ }
+ return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+}
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
new file mode 100644
index 0000000..e856569
--- /dev/null
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -0,0 +1,9 @@
+LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only
+ global:
+ RunRpcServer;
+ RunRpcServerCallback;
+ RpcClient;
+ RpcPreconnectedClient;
+ local:
+ *;
+};
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index b03e24c..79c8c8f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -32,28 +32,11 @@
],
}
-cc_defaults {
- name: "libbinder_ndk_host_user",
- target: {
- host: {
- cflags: [
- "-D__INTRODUCED_IN(n)=",
- "-D__assert(a,b,c)=",
- // We want all the APIs to be available on the host.
- "-D__ANDROID_API__=10000",
- ],
- },
- darwin: {
- enabled: false,
- },
- },
-}
-
cc_library {
name: "libbinder_ndk",
- defaults: ["libbinder_ndk_host_user"],
host_supported: true,
+ recovery_available: true,
llndk: {
symbol_file: "libbinder_ndk.map.txt",
@@ -117,6 +100,9 @@
"30",
],
},
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
tidy: true,
tidy_flags: [
// Only check our headers
@@ -152,6 +138,7 @@
name: "libbinder_headers_platform_shared",
export_include_dirs: ["include_cpp"],
vendor_available: true,
+ recovery_available: true,
host_supported: true,
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 1dcb41b..28e3ff4 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -47,7 +47,8 @@
void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
static void attach(const sp<IBinder>& binder) {
- binder->attachObject(kId, kValue, nullptr /*cookie*/, clean);
+ // can only attach once
+ CHECK_EQ(nullptr, binder->attachObject(kId, kValue, nullptr /*cookie*/, clean));
}
static bool has(const sp<IBinder>& binder) {
return binder != nullptr && binder->findObject(kId) == kValue;
@@ -57,7 +58,6 @@
namespace ABpBinderTag {
-static std::mutex gLock;
static const void* kId = "ABpBinder";
struct Value {
wp<ABpBinder> binder;
@@ -82,8 +82,8 @@
const String16& currentDescriptor = mClazz->getInterfaceDescriptor();
if (newDescriptor == currentDescriptor) {
LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
- << "' match during associateClass, but they are different class objects. "
- "Class descriptor collision?";
+ << "' match during associateClass, but they are different class objects ("
+ << clazz << " vs " << mClazz << "). Class descriptor collision?";
} else {
LOG(ERROR) << __func__
<< ": Class cannot be associated on object which already has a class. "
@@ -104,6 +104,17 @@
return {};
}
+// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
+static std::string SanitizeString(const String16& str) {
+ std::string sanitized{String8(str)};
+ for (auto& c : sanitized) {
+ if (!isprint(c)) {
+ c = '?';
+ }
+ }
+ return sanitized;
+}
+
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
if (clazz == nullptr) return false;
@@ -118,7 +129,7 @@
if (descriptor != newDescriptor) {
if (getBinder()->isBinderAlive()) {
LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
- << "' but descriptor is actually '" << descriptor << "'.";
+ << "' but descriptor is actually '" << SanitizeString(descriptor) << "'.";
} else {
// b/155793159
LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
@@ -172,7 +183,7 @@
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
if (isUserCommand(code)) {
- if (!data.checkInterface(this)) {
+ if (getClass()->writeHeader && !data.checkInterface(this)) {
return STATUS_BAD_TYPE;
}
@@ -232,19 +243,16 @@
ABpBinder::~ABpBinder() {}
void ABpBinder::onLastStrongRef(const void* id) {
- {
- std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
- // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
- // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no
- // longer be able to exist at the time of this method call, there is no longer a need to
- // recover it.
+ // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
+ // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
+ // (BpRefBase), the remote object may still exist (for instance, if we
+ // receive it from another process, before the ABpBinder is attached).
- ABpBinderTag::Value* value =
- static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
- if (value != nullptr) {
- value->binder = nullptr;
- }
- }
+ ABpBinderTag::Value* value =
+ static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
+ CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
+
+ remote()->withLock([&]() { value->binder = nullptr; });
BpRefBase::onLastStrongRef(id);
}
@@ -259,21 +267,29 @@
// The following code ensures that for a given binder object (remote or local), if it is not an
// ABBinder then at most one ABpBinder object exists in a given process representing it.
- std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
- ABpBinderTag::Value* value =
- static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
+ auto* value = static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
if (value == nullptr) {
value = new ABpBinderTag::Value;
- binder->attachObject(ABpBinderTag::kId, static_cast<void*>(value), nullptr /*cookie*/,
- ABpBinderTag::clean);
+ auto oldValue = static_cast<ABpBinderTag::Value*>(
+ binder->attachObject(ABpBinderTag::kId, static_cast<void*>(value),
+ nullptr /*cookie*/, ABpBinderTag::clean));
+
+ // allocated by another thread
+ if (oldValue) {
+ delete value;
+ value = oldValue;
+ }
}
- sp<ABpBinder> ret = value->binder.promote();
- if (ret == nullptr) {
- ret = new ABpBinder(binder);
- value->binder = ret;
- }
+ sp<ABpBinder> ret;
+ binder->withLock([&]() {
+ ret = value->binder.promote();
+ if (ret == nullptr) {
+ ret = sp<ABpBinder>::make(binder);
+ value->binder = ret;
+ }
+ });
return ret;
}
@@ -349,6 +365,12 @@
clazz->onDump = onDump;
}
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
+ CHECK(clazz != nullptr) << "disableInterfaceTokenHeader requires non-null clazz";
+
+ clazz->writeHeader = false;
+}
+
void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
AIBinder_handleShellCommand handleShellCommand) {
CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz";
@@ -362,6 +384,12 @@
return clazz->getInterfaceDescriptorUtf8();
}
+AIBinder_DeathRecipient::TransferDeathRecipient::~TransferDeathRecipient() {
+ if (mOnUnlinked != nullptr) {
+ mOnUnlinked(mCookie);
+ }
+}
+
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get()
<< " (" << mWho.get_refs() << ")";
@@ -383,7 +411,7 @@
}
AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
- : mOnDied(onDied) {
+ : mOnDied(onDied), mOnUnlinked(nullptr) {
CHECK(onDied != nullptr);
}
@@ -401,10 +429,12 @@
std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
sp<TransferDeathRecipient> recipient =
- new TransferDeathRecipient(binder, cookie, this, mOnDied);
+ new TransferDeathRecipient(binder, cookie, this, mOnDied, mOnUnlinked);
status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/);
if (status != STATUS_OK) {
+ // When we failed to link, the destructor of TransferDeathRecipient runs here, which
+ // ensures that mOnUnlinked is called before we return with an error from this method.
return PruneStatusT(status);
}
@@ -437,6 +467,10 @@
return STATUS_NAME_NOT_FOUND;
}
+void AIBinder_DeathRecipient::setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) {
+ mOnUnlinked = onUnlinked;
+}
+
// start of C-API methods
AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
@@ -532,6 +566,10 @@
return ::android::IPCThreadState::self()->getCallingPid();
}
+bool AIBinder_isHandlingTransaction() {
+ return ::android::IPCThreadState::self()->getServingStackPointer() != nullptr;
+}
+
void AIBinder_incStrong(AIBinder* binder) {
if (binder == nullptr) {
return;
@@ -601,7 +639,10 @@
*in = new AParcel(binder);
(*in)->get()->markForBinder(binder->getBinder());
- status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+ status_t status = android::OK;
+ if (clazz->writeHeader) {
+ status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+ }
binder_status_t ret = PruneStatusT(status);
if (ret != STATUS_OK) {
@@ -675,6 +716,15 @@
return ret;
}
+void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient,
+ AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) {
+ if (recipient == nullptr) {
+ return;
+ }
+
+ recipient->setOnUnlinked(onUnlinked);
+}
+
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) {
if (recipient == nullptr) {
return;
@@ -745,3 +795,16 @@
AIBinder_incStrong(ndkBinder.get());
return ndkBinder.get();
}
+
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) {
+ binder->asABBinder()->setMinSchedulerPolicy(policy, priority);
+}
+
+void AIBinder_setInheritRt(AIBinder* binder, bool inheritRt) {
+ ABBinder* localBinder = binder->asABBinder();
+ if (localBinder == nullptr) {
+ LOG(FATAL) << "AIBinder_setInheritRt must be called on a local binder";
+ }
+
+ localBinder->setInheritRt(inheritRt);
+}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 6824306..730e51b 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -105,6 +105,7 @@
ABpBinder* asABpBinder() override { return this; }
private:
+ friend android::sp<ABpBinder>;
explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
};
@@ -115,6 +116,9 @@
const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
+ // whether a transaction header should be written
+ bool writeHeader = true;
+
// required to be non-null, implemented for every class
const AIBinder_Class_onCreate onCreate = nullptr;
const AIBinder_Class_onDestroy onDestroy = nullptr;
@@ -144,8 +148,14 @@
struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
const ::android::wp<AIBinder_DeathRecipient>& parentRecipient,
- const AIBinder_DeathRecipient_onBinderDied onDied)
- : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {}
+ const AIBinder_DeathRecipient_onBinderDied onDied,
+ const AIBinder_DeathRecipient_onBinderUnlinked onUnlinked)
+ : mWho(who),
+ mCookie(cookie),
+ mParentRecipient(parentRecipient),
+ mOnDied(onDied),
+ mOnUnlinked(onUnlinked) {}
+ ~TransferDeathRecipient();
void binderDied(const ::android::wp<::android::IBinder>& who) override;
@@ -161,11 +171,13 @@
// This is kept separately from AIBinder_DeathRecipient in case the death recipient is
// deleted while the death notification is fired
const AIBinder_DeathRecipient_onBinderDied mOnDied;
+ const AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked;
};
explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie);
binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie);
+ void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked);
private:
// When the user of this API deletes a Bp object but not the death recipient, the
@@ -176,4 +188,5 @@
std::mutex mDeathRecipientsMutex;
std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
AIBinder_DeathRecipient_onBinderDied mOnDied;
+ AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked;
};
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 0ad400b..7ea9be7 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -163,6 +163,15 @@
const T get() const { return mT; }
/**
+ * Release the underlying resource.
+ */
+ [[nodiscard]] T release() {
+ T a = mT;
+ mT = DEFAULT;
+ return a;
+ }
+
+ /**
* This allows the value in this class to be set from beneath it. If you call this method and
* then change the value of T*, you must take ownership of the value you are replacing and add
* ownership to the object that is put in here.
@@ -259,7 +268,11 @@
const char* getMessage() const { return AStatus_getMessage(get()); }
std::string getDescription() const {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
+#else
+ if (__ANDROID_API__ >= 30) {
+#endif
const char* cStr = AStatus_getDescription(get());
std::string ret = cStr;
AStatus_deleteDescription(cStr);
@@ -365,6 +378,8 @@
ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
+ ScopedFileDescriptor dup() const { return ScopedFileDescriptor(::dup(get())); }
+
bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
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 6c44726..b3bc7f4 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -55,6 +55,12 @@
std::call_once(mFlagThis, [&]() {
__assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
});
+
+ if (ref() != nullptr) {
+ __assert(__FILE__, __LINE__,
+ "SharedRefBase: destructed but still able to lock weak_ptr. Is this object "
+ "double-owned?");
+ }
}
/**
@@ -184,9 +190,9 @@
BnCInterface() {}
virtual ~BnCInterface() {}
- SpAIBinder asBinder() override;
+ SpAIBinder asBinder() override final;
- bool isRemote() override { return false; }
+ bool isRemote() override final { return false; }
protected:
/**
@@ -209,9 +215,9 @@
explicit BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
virtual ~BpCInterface() {}
- SpAIBinder asBinder() override;
+ SpAIBinder asBinder() override final;
- bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+ bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); }
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
return AIBinder_dump(asBinder().get(), fd, args, numArgs);
@@ -250,7 +256,11 @@
// ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
#ifdef HAS_BINDER_SHELL_COMMAND
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 30, *)) {
+#else
+ if (__ANDROID_API__ >= 30) {
+#endif
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 83190aa..0bf1e3d 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -27,15 +27,146 @@
#pragma once
#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
#include <android/binder_internal_logging.h>
#include <android/binder_parcel.h>
+#include <array>
#include <optional>
#include <string>
+#include <type_traits>
#include <vector>
namespace ndk {
+namespace {
+template <typename Test, template <typename...> class Ref>
+struct is_specialization : std::false_type {};
+
+template <template <typename...> class Ref, typename... Args>
+struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
+
+template <typename Test, template <typename...> class Ref>
+static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+// Get the first template type from a container, the T from MyClass<T, ...>.
+template <typename T>
+struct first_template_type {
+ using type = void;
+};
+
+template <template <typename...> class V, typename T, typename... Args>
+struct first_template_type<V<T, Args...>> {
+ using type = T;
+};
+
+template <typename T>
+using first_template_type_t = typename first_template_type<T>::type;
+
+// Tells if T represents NDK interface (shared_ptr<ICInterface-derived>)
+template <typename T>
+static inline constexpr bool is_interface_v = is_specialization_v<T, std::shared_ptr>&&
+ std::is_base_of_v<::ndk::ICInterface, first_template_type_t<T>>;
+
+// Tells if T represents NDK parcelable with readFromParcel/writeToParcel methods defined
+template <typename T, typename = void>
+struct is_parcelable : std::false_type {};
+
+template <typename T>
+struct is_parcelable<
+ T, std::void_t<decltype(std::declval<T>().readFromParcel(std::declval<const AParcel*>())),
+ decltype(std::declval<T>().writeToParcel(std::declval<AParcel*>()))>>
+ : std::true_type {};
+
+template <typename T>
+static inline constexpr bool is_parcelable_v = is_parcelable<T>::value;
+
+// Tells if T represents nullable NDK parcelable (optional<parcelable> or unique_ptr<parcelable>)
+template <typename T>
+static inline constexpr bool is_nullable_parcelable_v = is_parcelable_v<first_template_type_t<T>> &&
+ (is_specialization_v<T, std::optional> ||
+ is_specialization_v<T, std::unique_ptr>);
+
+// Tells if T is a fixed-size array.
+template <typename T>
+struct is_fixed_array : std::false_type {};
+
+template <typename T, size_t N>
+struct is_fixed_array<std::array<T, N>> : std::true_type {};
+
+template <typename T>
+static inline constexpr bool is_fixed_array_v = is_fixed_array<T>::value;
+
+template <typename T>
+static inline constexpr bool dependent_false_v = false;
+} // namespace
+
+/**
+ * This checks the length against the array size and retrieves the buffer. No allocation required.
+ */
+template <typename T, size_t N>
+static inline bool AParcel_stdArrayAllocator(void* arrayData, int32_t length, T** outBuffer) {
+ if (length < 0) return false;
+
+ if (length != static_cast<int32_t>(N)) {
+ return false;
+ }
+
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
+ *outBuffer = arr->data();
+ return true;
+}
+
+/**
+ * This checks the length against the array size and retrieves the buffer. No allocation required.
+ */
+template <typename T, size_t N>
+static inline bool AParcel_nullableStdArrayAllocator(void* arrayData, int32_t length,
+ T** outBuffer) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
+ if (length < 0) {
+ *arr = std::nullopt;
+ return true;
+ }
+
+ if (length != static_cast<int32_t>(N)) {
+ return false;
+ }
+
+ arr->emplace();
+ *outBuffer = (*arr)->data();
+ return true;
+}
+
+/**
+ * This checks the length against the array size. No allocation required.
+ */
+template <size_t N>
+static inline bool AParcel_stdArrayExternalAllocator(void* arrayData, int32_t length) {
+ (void)arrayData;
+ return length == static_cast<int32_t>(N);
+}
+
+/**
+ * This checks the length against the array size. No allocation required.
+ */
+template <typename T, size_t N>
+static inline bool AParcel_nullableStdArrayExternalAllocator(void* arrayData, int32_t length) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
+
+ if (length < 0) {
+ *arr = std::nullopt;
+ return true;
+ }
+
+ if (length != static_cast<int32_t>(N)) {
+ return false;
+ }
+
+ arr->emplace();
+ return true;
+}
+
/**
* This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
@@ -345,6 +476,118 @@
}
/**
+ * This retrieves the underlying value in a std::array which may not be contiguous at index from a
+ * corresponding arrData.
+ */
+template <typename T, size_t N>
+static inline T AParcel_stdArrayGetter(const void* arrData, size_t index) {
+ const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrData);
+ return (*arr)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding arrData which may not be contiguous at
+ * index.
+ */
+template <typename T, size_t N>
+static inline void AParcel_stdArraySetter(void* arrData, size_t index, T value) {
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrData);
+ (*arr)[index] = value;
+}
+
+/**
+ * This retrieves the underlying value in a std::array which may not be contiguous at index from a
+ * corresponding arrData.
+ */
+template <typename T, size_t N>
+static inline T AParcel_nullableStdArrayGetter(const void* arrData, size_t index) {
+ const std::optional<std::array<T, N>>* arr =
+ static_cast<const std::optional<std::array<T, N>>*>(arrData);
+ return (*arr)[index];
+}
+
+/**
+ * This sets the underlying value in a corresponding arrData which may not be contiguous at
+ * index.
+ */
+template <typename T, size_t N>
+static inline void AParcel_nullableStdArraySetter(void* arrData, size_t index, T value) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrData);
+ (*arr)->at(index) = value;
+}
+
+/**
+ * Allocates a std::string inside of std::array<std::string, N> at index 'index' to size 'length'.
+ */
+template <size_t N>
+static inline bool AParcel_stdArrayStringElementAllocator(void* arrData, size_t index,
+ int32_t length, char** buffer) {
+ std::array<std::string, N>* arr = static_cast<std::array<std::string, N>*>(arrData);
+ std::string& element = arr->at(index);
+ return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a std::array<std::string, N> at index
+ * 'index'.
+ */
+template <size_t N>
+static const char* AParcel_stdArrayStringElementGetter(const void* arrData, size_t index,
+ int32_t* outLength) {
+ const std::array<std::string, N>* arr = static_cast<const std::array<std::string, N>*>(arrData);
+ const std::string& element = arr->at(index);
+
+ *outLength = static_cast<int32_t>(element.size());
+ return element.c_str();
+}
+
+/**
+ * Allocates a std::string inside of std::array<std::optional<std::string>, N> at index 'index' to
+ * size 'length'.
+ */
+template <size_t N>
+static inline bool AParcel_stdArrayNullableStringElementAllocator(void* arrData, size_t index,
+ int32_t length, char** buffer) {
+ std::array<std::optional<std::string>, N>* arr =
+ static_cast<std::array<std::optional<std::string>, N>*>(arrData);
+ std::optional<std::string>& element = arr->at(index);
+ return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::string inside of a
+ * std::array<std::optional<std::string>, N> at index 'index'.
+ */
+template <size_t N>
+static const char* AParcel_stdArrayNullableStringElementGetter(const void* arrData, size_t index,
+ int32_t* outLength) {
+ const std::array<std::optional<std::string>, N>* arr =
+ static_cast<const std::array<std::optional<std::string>, N>*>(arrData);
+ const std::optional<std::string>& element = arr->at(index);
+
+ if (!element) {
+ *outLength = -1;
+ return nullptr;
+ }
+
+ *outLength = static_cast<int32_t>(element->size());
+ return element->c_str();
+}
+
+/**
+ * Allocates a std::string inside of std::optional<std::array<std::optional<std::string>, N>> at
+ * index 'index' to size 'length'.
+ */
+template <size_t N>
+static inline bool AParcel_nullableStdArrayStringElementAllocator(void* arrData, size_t index,
+ int32_t length, char** buffer) {
+ std::optional<std::array<std::optional<std::string>, N>>* arr =
+ static_cast<std::optional<std::array<std::optional<std::string>, N>>*>(arrData);
+ std::optional<std::string>& element = (*arr)->at(index);
+ return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
* Convenience API for writing a std::string.
*/
static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
@@ -429,11 +672,17 @@
*/
template <typename P>
static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
+ if constexpr (is_interface_v<P>) {
+ // Legacy behavior: allow null
+ return first_template_type_t<P>::writeToParcel(parcel, p);
+ } else {
+ static_assert(is_parcelable_v<P>);
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p.writeToParcel(parcel);
}
- return p.writeToParcel(parcel);
}
/**
@@ -441,50 +690,134 @@
*/
template <typename P>
static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
- return status;
+ if constexpr (is_interface_v<P>) {
+ // Legacy behavior: allow null
+ return first_template_type_t<P>::readFromParcel(parcel, p);
+ } else {
+ static_assert(is_parcelable_v<P>);
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return p->readFromParcel(parcel);
}
- if (null == 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- return p->readFromParcel(parcel);
}
/**
* Convenience API for writing a nullable parcelable.
*/
template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
- const std::optional<P>& p) {
- if (p == std::nullopt) {
- return AParcel_writeInt32(parcel, 0); // null
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, const P& p) {
+ if constexpr (is_interface_v<P>) {
+ return first_template_type_t<P>::writeToParcel(parcel, p);
+ } else {
+ static_assert(is_nullable_parcelable_v<P>);
+ if (!p) {
+ return AParcel_writeInt32(parcel, 0); // null
+ }
+ binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return p->writeToParcel(parcel);
}
- binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null
- if (status != STATUS_OK) {
- return status;
- }
- return p->writeToParcel(parcel);
}
/**
* Convenience API for reading a nullable parcelable.
*/
template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
- std::optional<P>* p) {
- int32_t null;
- binder_status_t status = AParcel_readInt32(parcel, &null);
- if (status != STATUS_OK) {
- return status;
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, P* p) {
+ if constexpr (is_interface_v<P>) {
+ return first_template_type_t<P>::readFromParcel(parcel, p);
+ } else if constexpr (is_specialization_v<P, std::optional>) {
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ *p = std::nullopt;
+ return STATUS_OK;
+ }
+ p->emplace(first_template_type_t<P>());
+ return (*p)->readFromParcel(parcel);
+ } else {
+ static_assert(is_specialization_v<P, std::unique_ptr>);
+ int32_t null;
+ binder_status_t status = AParcel_readInt32(parcel, &null);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ if (null == 0) {
+ p->reset();
+ return STATUS_OK;
+ }
+ *p = std::make_unique<first_template_type_t<P>>();
+ return (*p)->readFromParcel(parcel);
}
- if (null == 0) {
- *p = std::nullopt;
- return STATUS_OK;
- }
- *p = std::optional<P>(P{});
- return (*p)->readFromParcel(parcel);
+}
+
+// Forward decls
+template <typename T>
+static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value);
+template <typename T>
+static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value);
+template <typename T>
+static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value);
+template <typename T>
+static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value);
+
+/**
+ * Reads an object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_readStdArrayData(const AParcel* parcel, void* arrayData, size_t index) {
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
+ return AParcel_readData(parcel, &arr->at(index));
+}
+
+/**
+ * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_readStdArrayNullableData(const AParcel* parcel, void* arrayData,
+ size_t index) {
+ std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
+ return AParcel_readNullableData(parcel, &arr->at(index));
+}
+
+/**
+ * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_readNullableStdArrayNullableData(const AParcel* parcel, void* arrayData,
+ size_t index) {
+ std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
+ return AParcel_readNullableData(parcel, &(*arr)->at(index));
+}
+
+/**
+ * Writes an object of type T inside a std::array<T, N> at index 'index' to 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_writeStdArrayData(AParcel* parcel, const void* arrayData, size_t index) {
+ const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData);
+ return AParcel_writeData(parcel, arr->at(index));
+}
+
+/**
+ * Writes a nullable object of type T inside a std::array<T, N> at index 'index' to 'parcel'.
+ */
+template <typename T, size_t N>
+binder_status_t AParcel_writeStdArrayNullableData(AParcel* parcel, const void* arrayData,
+ size_t index) {
+ const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData);
+ return AParcel_writeNullableData(parcel, arr->at(index));
}
/**
@@ -508,6 +841,28 @@
}
/**
+ * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_writeNullableStdVectorParcelableElement(AParcel* parcel,
+ const void* vectorData,
+ size_t index) {
+ const std::optional<std::vector<P>>* vector =
+ static_cast<const std::optional<std::vector<P>>*>(vectorData);
+ return AParcel_writeNullableParcelable(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_readNullableStdVectorParcelableElement(const AParcel* parcel,
+ void* vectorData, size_t index) {
+ std::optional<std::vector<P>>* vector = static_cast<std::optional<std::vector<P>>*>(vectorData);
+ return AParcel_readNullableParcelable(parcel, &(*vector)->at(index));
+}
+
+/**
* Writes a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index'
* to 'parcel'.
*/
@@ -516,11 +871,7 @@
AParcel* parcel, const void* vectorData, size_t index) {
const std::vector<ScopedFileDescriptor>* vector =
static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData);
- int writeFd = vector->at(index).get();
- if (writeFd < 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- return AParcel_writeParcelFileDescriptor(parcel, writeFd);
+ return AParcel_writeRequiredParcelFileDescriptor(parcel, vector->at(index));
}
/**
@@ -532,15 +883,79 @@
const AParcel* parcel, void* vectorData, size_t index) {
std::vector<ScopedFileDescriptor>* vector =
static_cast<std::vector<ScopedFileDescriptor>*>(vectorData);
- int readFd;
- binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
- if (status == STATUS_OK) {
- if (readFd < 0) {
- return STATUS_UNEXPECTED_NULL;
- }
- vector->at(index).set(readFd);
- }
- return status;
+ return AParcel_readRequiredParcelFileDescriptor(parcel, &vector->at(index));
+}
+
+/**
+ * Writes a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+ AParcel* parcel, const void* vectorData, size_t index) {
+ const std::optional<std::vector<ScopedFileDescriptor>>* vector =
+ static_cast<const std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+ return AParcel_writeNullableParcelFileDescriptor(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+ const AParcel* parcel, void* vectorData, size_t index) {
+ std::optional<std::vector<ScopedFileDescriptor>>* vector =
+ static_cast<std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+ return AParcel_readNullableParcelFileDescriptor(parcel, &(*vector)->at(index));
+}
+
+/**
+ * Writes an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
+ * to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeStdVectorParcelableElement<SpAIBinder>(AParcel* parcel,
+ const void* vectorData,
+ size_t index) {
+ const std::vector<SpAIBinder>* vector = static_cast<const std::vector<SpAIBinder>*>(vectorData);
+ return AParcel_writeRequiredStrongBinder(parcel, vector->at(index));
+}
+
+/**
+ * Reads an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
+ * from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readStdVectorParcelableElement<SpAIBinder>(const AParcel* parcel,
+ void* vectorData,
+ size_t index) {
+ std::vector<SpAIBinder>* vector = static_cast<std::vector<SpAIBinder>*>(vectorData);
+ return AParcel_readRequiredStrongBinder(parcel, &vector->at(index));
+}
+
+/**
+ * Writes an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
+ * to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<SpAIBinder>(
+ AParcel* parcel, const void* vectorData, size_t index) {
+ const std::optional<std::vector<SpAIBinder>>* vector =
+ static_cast<const std::optional<std::vector<SpAIBinder>>*>(vectorData);
+ return AParcel_writeNullableStrongBinder(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
+ * from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<SpAIBinder>(
+ const AParcel* parcel, void* vectorData, size_t index) {
+ std::optional<std::vector<SpAIBinder>>* vector =
+ static_cast<std::optional<std::vector<SpAIBinder>>*>(vectorData);
+ return AParcel_readNullableStrongBinder(parcel, &(*vector)->at(index));
}
/**
@@ -548,9 +963,25 @@
*/
template <typename P>
static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
- const void* vectorData = static_cast<const void*>(&vec);
- return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
- AParcel_writeStdVectorParcelableElement<P>);
+ if constexpr (std::is_enum_v<P>) {
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_writeInt32Array(parcel, reinterpret_cast<const int32_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_writeInt64Array(parcel, reinterpret_cast<const int64_t*>(vec.data()),
+ static_cast<int32_t>(vec.size()));
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::string>, "specialization should be used");
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
+ AParcel_writeStdVectorParcelableElement<P>);
+ }
}
/**
@@ -558,9 +989,86 @@
*/
template <typename P>
static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readParcelableArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<P>,
- AParcel_readStdVectorParcelableElement<P>);
+ if constexpr (std::is_enum_v<P>) {
+ void* vectorData = static_cast<void*>(vec);
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::string>, "specialization should be used");
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readParcelableArray(parcel, vectorData,
+ AParcel_stdVectorExternalAllocator<P>,
+ AParcel_readStdVectorParcelableElement<P>);
+ }
+}
+
+/**
+ * Convenience API for writing a std::optional<std::vector<P>>
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<P>>& vec) {
+ if constexpr (std::is_enum_v<P>) {
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_writeByteArray(
+ parcel, vec ? reinterpret_cast<const int8_t*>(vec->data()) : nullptr,
+ vec ? static_cast<int32_t>(vec->size()) : -1);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_writeInt32Array(
+ parcel, vec ? reinterpret_cast<const int32_t*>(vec->data()) : nullptr,
+ vec ? static_cast<int32_t>(vec->size()) : -1);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_writeInt64Array(
+ parcel, vec ? reinterpret_cast<const int64_t*>(vec->data()) : nullptr,
+ vec ? static_cast<int32_t>(vec->size()) : -1);
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::optional<std::string>>,
+ "specialization should be used");
+ if (!vec) return AParcel_writeInt32(parcel, -1);
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()),
+ AParcel_writeNullableStdVectorParcelableElement<P>);
+ }
+}
+
+/**
+ * Convenience API for reading a std::optional<std::vector<P>>
+ */
+template <typename P>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<P>>* vec) {
+ if constexpr (std::is_enum_v<P>) {
+ void* vectorData = static_cast<void*>(vec);
+ if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
+ return AParcel_readByteArray(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<int8_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
+ return AParcel_readInt32Array(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<int32_t>);
+ } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
+ return AParcel_readInt64Array(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<int64_t>);
+ } else {
+ static_assert(dependent_false_v<P>, "unrecognized type");
+ }
+ } else {
+ static_assert(!std::is_same_v<P, std::optional<std::string>>,
+ "specialization should be used");
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readParcelableArray(parcel, vectorData,
+ AParcel_nullableStdVectorExternalAllocator<P>,
+ AParcel_readNullableStdVectorParcelableElement<P>);
+ }
}
// @START
@@ -910,6 +1418,9 @@
if (err != STATUS_OK) return err;
if (size < 0) return STATUS_UNEXPECTED_NULL;
+ // TODO(b/188215728): delegate to libbinder_ndk
+ if (size > 1000000) return STATUS_NO_MEMORY;
+
vec->resize(static_cast<size_t>(size));
return STATUS_OK;
}
@@ -931,11 +1442,302 @@
return STATUS_OK;
}
+ // TODO(b/188215728): delegate to libbinder_ndk
+ if (size > 1000000) return STATUS_NO_MEMORY;
+
*vec = std::optional<std::vector<T>>(std::vector<T>{});
(*vec)->resize(static_cast<size_t>(size));
return STATUS_OK;
}
+/**
+ * Writes a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_writeFixedArray(AParcel* parcel,
+ const std::array<T, N>& arr) {
+ if constexpr (std::is_same_v<T, bool>) {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeBoolArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_stdArrayGetter<T, N>);
+ } else if constexpr (std::is_same_v<T, uint8_t>) {
+ return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(arr.data()),
+ static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, char16_t>) {
+ return AParcel_writeCharArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return AParcel_writeInt32Array(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return AParcel_writeInt64Array(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, float>) {
+ return AParcel_writeFloatArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, double>) {
+ return AParcel_writeDoubleArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_stdArrayStringElementGetter<N>);
+ } else {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_writeStdArrayData<T, N>);
+ }
+}
+
+/**
+ * Writes a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_writeFixedArrayWithNullableData(AParcel* parcel,
+ const std::array<T, N>& arr) {
+ if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> ||
+ std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> ||
+ std::is_same_v<T, int64_t> || std::is_same_v<T, float> ||
+ std::is_same_v<T, double> || std::is_same_v<T, std::string>) {
+ return AParcel_writeFixedArray(parcel, arr);
+ } else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_stdArrayNullableStringElementGetter<N>);
+ } else {
+ const void* arrayData = static_cast<const void*>(&arr);
+ return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N),
+ &AParcel_writeStdArrayNullableData<T, N>);
+ }
+}
+
+/**
+ * Writes a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_writeNullableFixedArrayWithNullableData(
+ AParcel* parcel, const std::optional<std::array<T, N>>& arr) {
+ if (!arr) return AParcel_writeInt32(parcel, -1);
+ return AParcel_writeFixedArrayWithNullableData(parcel, arr.value());
+}
+
+/**
+ * Reads a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_readFixedArray(const AParcel* parcel, std::array<T, N>* arr) {
+ void* arrayData = static_cast<void*>(arr);
+ if constexpr (std::is_same_v<T, bool>) {
+ return AParcel_readBoolArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_stdArraySetter<T, N>);
+ } else if constexpr (std::is_same_v<T, uint8_t>) {
+ return AParcel_readByteArray(parcel, arrayData, &AParcel_stdArrayAllocator<int8_t, N>);
+ } else if constexpr (std::is_same_v<T, char16_t>) {
+ return AParcel_readCharArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return AParcel_readInt32Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return AParcel_readInt64Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, float>) {
+ return AParcel_readFloatArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, double>) {
+ return AParcel_readDoubleArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_stdArrayStringElementAllocator<N>);
+ } else {
+ return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_readStdArrayData<T, N>);
+ }
+}
+
+/**
+ * Reads a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_readFixedArrayWithNullableData(const AParcel* parcel,
+ std::array<T, N>* arr) {
+ void* arrayData = static_cast<void*>(arr);
+ if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> ||
+ std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> ||
+ std::is_same_v<T, int64_t> || std::is_same_v<T, float> ||
+ std::is_same_v<T, double> || std::is_same_v<T, std::string>) {
+ return AParcel_readFixedArray(parcel, arr);
+ } else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
+ return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_stdArrayNullableStringElementAllocator<N>);
+ } else {
+ return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
+ &AParcel_readStdArrayNullableData<T, N>);
+ }
+}
+
+/**
+ * Reads a fixed-size array of T.
+ */
+template <typename T, size_t N>
+static inline binder_status_t AParcel_readNullableFixedArrayWithNullableData(
+ const AParcel* parcel, std::optional<std::array<T, N>>* arr) {
+ void* arrayData = static_cast<void*>(arr);
+ if constexpr (std::is_same_v<T, bool>) {
+ return AParcel_readBoolArray(parcel, arrayData,
+ &AParcel_nullableStdArrayExternalAllocator<T, N>,
+ &AParcel_nullableStdArraySetter<T, N>);
+ } else if constexpr (std::is_same_v<T, uint8_t>) {
+ return AParcel_readByteArray(parcel, arrayData,
+ &AParcel_nullableStdArrayAllocator<int8_t, N>);
+ } else if constexpr (std::is_same_v<T, char16_t>) {
+ return AParcel_readCharArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ return AParcel_readInt32Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ return AParcel_readInt64Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, float>) {
+ return AParcel_readFloatArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, double>) {
+ return AParcel_readDoubleArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ return AParcel_readStringArray(parcel, arrayData,
+ &AParcel_nullableStdArrayExternalAllocator<N>,
+ &AParcel_nullableStdArrayStringElementAllocator<N>);
+ } else {
+ return AParcel_readParcelableArray(parcel, arrayData,
+ &AParcel_nullableStdArrayExternalAllocator<T, N>,
+ &AParcel_readStdArrayNullableData<T, N>);
+ }
+}
+
+/**
+ * Convenience API for writing a value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value) {
+ if constexpr (is_specialization_v<T, std::vector>) {
+ return AParcel_writeVector(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) {
+ return AParcel_writeFixedArray(parcel, value);
+ } else if constexpr (std::is_same_v<std::string, T>) {
+ return AParcel_writeString(parcel, value);
+ } else if constexpr (std::is_same_v<bool, T>) {
+ return AParcel_writeBool(parcel, value);
+ } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) {
+ return AParcel_writeByte(parcel, value);
+ } else if constexpr (std::is_same_v<char16_t, T>) {
+ return AParcel_writeChar(parcel, value);
+ } else if constexpr (std::is_same_v<int32_t, T>) {
+ return AParcel_writeInt32(parcel, value);
+ } else if constexpr (std::is_same_v<int64_t, T>) {
+ return AParcel_writeInt64(parcel, value);
+ } else if constexpr (std::is_same_v<float, T>) {
+ return AParcel_writeFloat(parcel, value);
+ } else if constexpr (std::is_same_v<double, T>) {
+ return AParcel_writeDouble(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_writeRequiredParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_writeRequiredStrongBinder(parcel, value);
+ } else if constexpr (std::is_enum_v<T>) {
+ return AParcel_writeData(parcel, static_cast<std::underlying_type_t<T>>(value));
+ } else if constexpr (is_interface_v<T>) {
+ return AParcel_writeParcelable(parcel, value);
+ } else if constexpr (is_parcelable_v<T>) {
+ return AParcel_writeParcelable(parcel, value);
+ } else {
+ static_assert(dependent_false_v<T>, "unrecognized type");
+ return STATUS_OK;
+ }
+}
+
+/**
+ * Convenience API for writing a nullable value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value) {
+ if constexpr (is_specialization_v<T, std::optional> &&
+ is_specialization_v<first_template_type_t<T>, std::vector>) {
+ return AParcel_writeVector(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ is_fixed_array_v<first_template_type_t<T>>) {
+ return AParcel_writeNullableFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) { // happens with a nullable multi-dimensional array.
+ return AParcel_writeFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ std::is_same_v<first_template_type_t<T>, std::string>) {
+ return AParcel_writeString(parcel, value);
+ } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) {
+ return AParcel_writeNullableParcelable(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_writeNullableParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_writeNullableStrongBinder(parcel, value);
+ } else {
+ return AParcel_writeData(parcel, value);
+ }
+}
+
+/**
+ * Convenience API for reading a value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value) {
+ if constexpr (is_specialization_v<T, std::vector>) {
+ return AParcel_readVector(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) {
+ return AParcel_readFixedArray(parcel, value);
+ } else if constexpr (std::is_same_v<std::string, T>) {
+ return AParcel_readString(parcel, value);
+ } else if constexpr (std::is_same_v<bool, T>) {
+ return AParcel_readBool(parcel, value);
+ } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) {
+ return AParcel_readByte(parcel, value);
+ } else if constexpr (std::is_same_v<char16_t, T>) {
+ return AParcel_readChar(parcel, value);
+ } else if constexpr (std::is_same_v<int32_t, T>) {
+ return AParcel_readInt32(parcel, value);
+ } else if constexpr (std::is_same_v<int64_t, T>) {
+ return AParcel_readInt64(parcel, value);
+ } else if constexpr (std::is_same_v<float, T>) {
+ return AParcel_readFloat(parcel, value);
+ } else if constexpr (std::is_same_v<double, T>) {
+ return AParcel_readDouble(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_readRequiredParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_readRequiredStrongBinder(parcel, value);
+ } else if constexpr (std::is_enum_v<T>) {
+ return AParcel_readData(parcel, reinterpret_cast<std::underlying_type_t<T>*>(value));
+ } else if constexpr (is_interface_v<T>) {
+ return AParcel_readParcelable(parcel, value);
+ } else if constexpr (is_parcelable_v<T>) {
+ return AParcel_readParcelable(parcel, value);
+ } else {
+ static_assert(dependent_false_v<T>, "unrecognized type");
+ return STATUS_OK;
+ }
+}
+
+/**
+ * Convenience API for reading a nullable value of any type.
+ */
+template <typename T>
+static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value) {
+ if constexpr (is_specialization_v<T, std::optional> &&
+ is_specialization_v<first_template_type_t<T>, std::vector>) {
+ return AParcel_readVector(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ is_fixed_array_v<first_template_type_t<T>>) {
+ return AParcel_readNullableFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_fixed_array_v<T>) { // happens with a nullable multi-dimensional array.
+ return AParcel_readFixedArrayWithNullableData(parcel, value);
+ } else if constexpr (is_specialization_v<T, std::optional> &&
+ std::is_same_v<first_template_type_t<T>, std::string>) {
+ return AParcel_readString(parcel, value);
+ } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) {
+ return AParcel_readNullableParcelable(parcel, value);
+ } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
+ return AParcel_readNullableParcelFileDescriptor(parcel, value);
+ } else if constexpr (std::is_same_v<SpAIBinder, T>) {
+ return AParcel_readNullableStrongBinder(parcel, value);
+ } else {
+ return AParcel_readData(parcel, value);
+ }
+}
+
} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 2277148..f45aa76 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -47,17 +47,41 @@
explicit AParcelableHolder(parcelable_stability_t stability)
: mParcel(AParcel_create()), mStability(stability) {}
+#if __ANDROID_API__ >= 31
+ AParcelableHolder(const AParcelableHolder& other)
+ : mParcel(AParcel_create()), mStability(other.mStability) {
+ // AParcelableHolder has been introduced in 31.
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
+ if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
+ AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
+ AParcel_getDataSize(other.mParcel.get()));
+ }
+ }
+#endif
+
+ AParcelableHolder(AParcelableHolder&& other) = default;
virtual ~AParcelableHolder() = default;
binder_status_t writeToParcel(AParcel* parcel) const {
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
int32_t size = AParcel_getDataSize(this->mParcel.get());
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
} else {
return STATUS_INVALID_OPERATION;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
int32_t size = AParcel_getDataSize(this->mParcel.get());
RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
} else {
@@ -67,13 +91,22 @@
}
binder_status_t readFromParcel(const AParcel* parcel) {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
} else {
return STATUS_INVALID_OPERATION;
}
- RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+ parcelable_stability_t wireStability;
+ RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
+ if (this->mStability != wireStability) {
+ return STATUS_BAD_VALUE;
+ }
+
int32_t dataSize;
binder_status_t status = AParcel_readInt32(parcel, &dataSize);
@@ -87,7 +120,11 @@
return STATUS_BAD_VALUE;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
} else {
status = STATUS_INVALID_OPERATION;
@@ -103,7 +140,11 @@
if (this->mStability > T::_aidl_stability) {
return STATUS_BAD_VALUE;
}
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
} else {
return STATUS_INVALID_OPERATION;
@@ -117,7 +158,11 @@
binder_status_t getParcelable(std::optional<T>* ret) const {
const std::string parcelableDesc(T::descriptor);
AParcel_setDataPosition(mParcel.get(), 0);
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
if (AParcel_getDataSize(mParcel.get()) == 0) {
*ret = std::nullopt;
return STATUS_OK;
@@ -141,7 +186,11 @@
}
void reset() {
+#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
if (__builtin_available(android 31, *)) {
+#else
+ if (__ANDROID_API__ >= 31) {
+#endif
AParcel_reset(mParcel.get());
}
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 78f2d3a..565542b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -219,6 +219,21 @@
void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
/**
+ * This tells users of this class not to use a transaction header. By default, libbinder_ndk users
+ * read/write transaction headers implicitly (in the SDK, this must be manually written by
+ * android.os.Parcel#writeInterfaceToken, and it is read/checked with
+ * android.os.Parcel#enforceInterface). This method is provided in order to talk to legacy code
+ * which does not write an interface token. When this is disabled, type safety is reduced, so you
+ * must have a separate way of determining the binder you are talking to is the right type. Must
+ * be called before any instance of the class is created.
+ *
+ * Available since API level 33.
+ *
+ * \param clazz class to disable interface header on.
+ */
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(33);
+
+/**
* Creates a new binder object of the appropriate class.
*
* Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
@@ -304,9 +319,9 @@
/**
* Registers for notifications that the associated binder is dead. The same death recipient may be
* associated with multiple different binders. If the binder is local, then no death recipient will
- * be given (since if the local process dies, then no recipient will exist to recieve a
+ * be given (since if the local process dies, then no recipient will exist to receive a
* transaction). The cookie is passed to recipient in the case that this binder dies and can be
- * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
+ * null. The exact cookie must also be used to unlink this transaction (see AIBinder_unlinkToDeath).
* This function may return a binder transaction failure. The cookie can be used both for
* identification and holding user data.
*
@@ -333,6 +348,10 @@
* If the binder dies, it will automatically unlink. If the binder is deleted, it will be
* automatically unlinked.
*
+ * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you
+ * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using
+ * AIBinder_DeathRecipient_setOnUnlinked.
+ *
* Available since API level 29.
*
* \param binder the binder object to remove a previously linked death recipient from.
@@ -374,6 +393,14 @@
pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29);
/**
+ * Determine whether the current thread is currently executing an incoming transaction.
+ *
+ * \return true if the current thread is currently executing an incoming transaction, and false
+ * otherwise.
+ */
+bool AIBinder_isHandlingTransaction() __INTRODUCED_IN(33);
+
+/**
* This can only be called if a strong reference to this object already exists in process.
*
* Available since API level 29.
@@ -553,6 +580,22 @@
typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
/**
+ * This function is intended for cleaning up the data in the provided cookie, and it is executed
+ * when the DeathRecipient is unlinked. When the DeathRecipient is unlinked due to a death receipt,
+ * this method is called after the call to onBinderDied.
+ *
+ * This method is called once for each binder that is unlinked. Hence, if the same cookie is passed
+ * to multiple binders, then the caller is responsible for reference counting the cookie.
+ *
+ * See also AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * Available since API level 33.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
+ */
+typedef void (*AIBinder_DeathRecipient_onBinderUnlinked)(void* cookie) __INTRODUCED_IN(33);
+
+/**
* Creates a new binder death recipient. This can be attached to multiple different binder objects.
*
* Available since API level 29.
@@ -565,9 +608,47 @@
AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
/**
+ * Set the callback to be called when this DeathRecipient is unlinked from a binder. The callback is
+ * called in the following situations:
+ *
+ * 1. If the binder died, shortly after the call to onBinderDied.
+ * 2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or
+ * AIBinder_DeathRecipient_delete.
+ * 3. During or shortly after the AIBinder_linkToDeath call if it returns an error.
+ *
+ * It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the
+ * process is aborted before the binder is unlinked.
+ *
+ * Be aware that when the binder is explicitly unlinked, it is not guaranteed that onUnlinked has
+ * been called before the call to AIBinder_unlinkToDeath or AIBinder_DeathRecipient_delete returns.
+ * For example, if the binder dies concurrently with a call to AIBinder_unlinkToDeath, the binder is
+ * not unlinked until after the death notification is delivered, even if AIBinder_unlinkToDeath
+ * returns before that happens.
+ *
+ * This method should be called before linking the DeathRecipient to a binder because the function
+ * pointer is cached. If you change it after linking to a binder, it is unspecified whether the old
+ * binder will call the old or new onUnlinked callback.
+ *
+ * The onUnlinked argument may be null. In this case, no notification is given when the binder is
+ * unlinked.
+ *
+ * Available since API level 33.
+ *
+ * \param recipient the DeathRecipient to set the onUnlinked callback for.
+ * \param onUnlinked the callback to call when a binder is unlinked from recipient.
+ */
+void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient,
+ AIBinder_DeathRecipient_onBinderUnlinked onUnlinked)
+ __INTRODUCED_IN(33);
+
+/**
* Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
* calling this as these will all be automatically unlinked.
*
+ * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you
+ * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using
+ * AIBinder_DeathRecipient_setOnUnlinked.
+ *
* Available since API level 29.
*
* \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 527b151..8457581 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1163,6 +1163,45 @@
* \return A parcel which is not related to any IBinder objects.
*/
AParcel* AParcel_create() __INTRODUCED_IN(31);
+
+/**
+ * Marshals the raw bytes of the Parcel to a buffer.
+ *
+ * Available since API level 33.
+ *
+ * The parcel must not contain any binders or file descriptors.
+ *
+ * The data you retrieve here must not be placed in any kind of persistent storage. (on local disk,
+ * across a network, etc). For that, you should use standard serialization or another kind of
+ * general serialization mechanism. The Parcel marshalled representation is highly optimized for
+ * local IPC, and as such does not attempt to maintain compatibility with data created in different
+ * versions of the platform.
+ *
+ * \param parcel The parcel of which to get the data.
+ * \param buffer The buffer to copy the raw bytes to.
+ * \param start The start position in the buffer to copy from.
+ * \param len The size of the data to copy, buffer size must be larger or equal to this.
+ *
+ * \return STATUS_OK on success, STATUS_INVALID_OPERATION if parcel contains binders or file
+ * descriptors. STATUS_BAD_VALUE if the buffer size is less than parcel size.
+ */
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len)
+ __INTRODUCED_IN(33);
+
+/**
+ * Set the data in the parcel to the raw bytes from the buffer.
+ *
+ * Available since API level 33.
+ *
+ * \param parcel The parcel to set data.
+ * \param buffer The data buffer to set.
+ * \param len The size of the data to set.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len)
+ __INTRODUCED_IN(33);
+
__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 6f1fdfc..76c7aac 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -32,11 +32,26 @@
__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.
+#ifndef __BIONIC__
+
+#ifndef __INTRODUCED_IN
+#define __INTRODUCED_IN(n)
#endif
+#ifndef __assert
+#define __assert(a, b, c) \
+ do { \
+ syslog(LOG_ERR, a ": " c); \
+ abort(); \
+ } while (false)
+#endif
+
+#ifndef __ANDROID_API__
+#define __ANDROID_API__ 10000
+#endif
+
+#endif // __BIONIC__
+
/**
* 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,
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index e315c79..89f21dd 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -55,4 +55,29 @@
*/
__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
+/**
+ * Sets a minimum scheduler policy for all transactions coming into this
+ * AIBinder.
+ *
+ * This must be called before the object is sent to another process.
+ * Aborts on invalid values. Not thread safe.
+ *
+ * \param binder local server binder to set the policy for
+ * \param policy scheduler policy as defined in linux UAPI
+ * \param priority priority. [-20..19] for SCHED_NORMAL, [1..99] for RT
+ */
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) __INTRODUCED_IN(33);
+
+/**
+ * Allow the binder to inherit realtime scheduling policies from its caller.
+ *
+ * This must be called before the object is sent to another process. Not thread
+ * safe.
+ *
+ * \param binder local server binder to set the policy for
+ * \param inheritRt whether to inherit realtime scheduling policies (default is
+ * false).
+ */
+void AIBinder_setInheritRt(AIBinder* binder, bool inheritRt) __INTRODUCED_IN(33);
+
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 2a66941..dfa8ea2 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -53,11 +53,19 @@
/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
- * for calling AIBinder_decStrong).
+ * for calling AIBinder_decStrong). This does polling. A more efficient way to make sure you
+ * unblock as soon as the service is available is to use AIBinder_waitForService.
*
* WARNING: when using this API across an APEX boundary, do not use with unstable
* AIDL services. TODO(b/139325195)
*
+ * WARNING: when using this API, typically, you should call it in a loop. It's dangerous to
+ * assume that nullptr could mean that the service is not available. The service could just
+ * be starting. Generally, whether a service exists, this information should be declared
+ * externally (for instance, an Android feature might imply the existence of a service,
+ * a system property, or in the case of services in the VINTF manifest, it can be checked
+ * with AServiceManager_isDeclared).
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
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 6372449..b24094e 100644
--- a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
@@ -33,7 +33,6 @@
#endif
-#if !defined(__ANDROID_APEX__)
/**
* Data written to the parcel will be zero'd before being deleted or realloced.
*
@@ -44,6 +43,5 @@
* \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 f113ba8..d0cd11f 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -97,6 +97,10 @@
*
* This interface has system<->vendor stability
*/
+// b/227835797 - can't use __INTRODUCED_IN(30) because old targets load this code
+#if __ANDROID_MIN_SDK_VERSION__ < 30
+__attribute__((weak))
+#endif // __ANDROID_MIN_SDK_VERSION__ < 30
void AIBinder_markVintfStability(AIBinder* binder);
__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 7d4b82e..3824a1b 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -117,13 +117,13 @@
ABinderProcess_setupPolling; # apex
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
- AParcel_markSensitive; # llndk
+ AParcel_markSensitive; # systemapi llndk
AServiceManager_forEachDeclaredInstance; # apex llndk
- AServiceManager_forceLazyServicesPersist; # llndk
+ AServiceManager_forceLazyServicesPersist; # apex llndk
AServiceManager_isDeclared; # apex llndk
AServiceManager_isUpdatableViaApex; # apex
AServiceManager_reRegister; # llndk
- AServiceManager_registerLazyService; # llndk
+ AServiceManager_registerLazyService; # apex llndk
AServiceManager_setActiveServicesCallback; # llndk
AServiceManager_tryUnregister; # llndk
AServiceManager_waitForService; # apex llndk
@@ -141,6 +141,17 @@
AParcel_reset;
};
+LIBBINDER_NDK33 { # introduced=33
+ global:
+ AIBinder_Class_disableInterfaceTokenHeader;
+ AIBinder_DeathRecipient_setOnUnlinked;
+ AIBinder_isHandlingTransaction;
+ AIBinder_setInheritRt; # llndk
+ AIBinder_setMinSchedulerPolicy; # llndk
+ AParcel_marshal;
+ AParcel_unmarshal;
+};
+
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index ec7c7d8..c320e8d 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -46,7 +46,8 @@
template <typename T>
using ArraySetter = void (*)(void* arrayData, size_t index, T value);
-binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int32_t length) {
+static binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray,
+ int32_t length) {
// only -1 can be used to represent a null array
if (length < -1) return STATUS_BAD_VALUE;
@@ -61,12 +62,24 @@
Parcel* rawParcel = parcel->get();
- status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
+ status_t status = rawParcel->writeInt32(length);
if (status != STATUS_OK) return PruneStatusT(status);
return STATUS_OK;
}
+static binder_status_t ReadAndValidateArraySize(const AParcel* parcel, int32_t* length) {
+ if (status_t status = parcel->get()->readInt32(length); status != STATUS_OK) {
+ return PruneStatusT(status);
+ }
+
+ if (*length < -1) return STATUS_BAD_VALUE; // libbinder_ndk reserves these
+ if (*length <= 0) return STATUS_OK; // null
+ if (static_cast<size_t>(*length) > parcel->get()->dataAvail()) return STATUS_NO_MEMORY;
+
+ return STATUS_OK;
+}
+
template <typename T>
binder_status_t WriteArray(AParcel* parcel, const T* array, int32_t length) {
binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
@@ -111,10 +124,9 @@
const Parcel* rawParcel = parcel->get();
int32_t length;
- status_t status = rawParcel->readInt32(&length);
-
- if (status != STATUS_OK) return PruneStatusT(status);
- if (length < -1) return STATUS_BAD_VALUE;
+ if (binder_status_t status = ReadAndValidateArraySize(parcel, &length); status != STATUS_OK) {
+ return status;
+ }
T* array;
if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
@@ -140,10 +152,9 @@
const Parcel* rawParcel = parcel->get();
int32_t length;
- status_t status = rawParcel->readInt32(&length);
-
- if (status != STATUS_OK) return PruneStatusT(status);
- if (length < -1) return STATUS_BAD_VALUE;
+ if (binder_status_t status = ReadAndValidateArraySize(parcel, &length); status != STATUS_OK) {
+ return status;
+ }
char16_t* array;
if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
@@ -155,7 +166,7 @@
if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
for (int32_t i = 0; i < length; i++) {
- status = rawParcel->readChar(array + i);
+ status_t status = rawParcel->readChar(array + i);
if (status != STATUS_OK) return PruneStatusT(status);
}
@@ -189,10 +200,9 @@
const Parcel* rawParcel = parcel->get();
int32_t length;
- status_t status = rawParcel->readInt32(&length);
-
- if (status != STATUS_OK) return PruneStatusT(status);
- if (length < -1) return STATUS_BAD_VALUE;
+ if (binder_status_t status = ReadAndValidateArraySize(parcel, &length); status != STATUS_OK) {
+ return status;
+ }
if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
@@ -200,7 +210,7 @@
for (int32_t i = 0; i < length; i++) {
T readTarget;
- status = (rawParcel->*read)(&readTarget);
+ status_t status = (rawParcel->*read)(&readTarget);
if (status != STATUS_OK) return PruneStatusT(status);
setter(arrayData, i, readTarget);
@@ -402,13 +412,10 @@
binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
AParcel_stringArrayAllocator allocator,
AParcel_stringArrayElementAllocator elementAllocator) {
- const Parcel* rawParcel = parcel->get();
-
int32_t length;
- status_t status = rawParcel->readInt32(&length);
-
- if (status != STATUS_OK) return PruneStatusT(status);
- if (length < -1) return STATUS_BAD_VALUE;
+ if (binder_status_t status = ReadAndValidateArraySize(parcel, &length); status != STATUS_OK) {
+ return status;
+ }
if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
@@ -449,13 +456,10 @@
binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayData,
AParcel_parcelableArrayAllocator allocator,
AParcel_readParcelableElement elementReader) {
- const Parcel* rawParcel = parcel->get();
-
int32_t length;
- status_t status = rawParcel->readInt32(&length);
-
- if (status != STATUS_OK) return PruneStatusT(status);
- if (length < -1) return STATUS_BAD_VALUE;
+ if (binder_status_t status = ReadAndValidateArraySize(parcel, &length); status != STATUS_OK) {
+ return status;
+ }
if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
@@ -669,4 +673,32 @@
return new AParcel(nullptr);
}
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len) {
+ if (parcel->get()->objectsCount()) {
+ return STATUS_INVALID_OPERATION;
+ }
+ int32_t dataSize = AParcel_getDataSize(parcel);
+ if (len > static_cast<size_t>(dataSize) || start > static_cast<size_t>(dataSize) - len) {
+ return STATUS_BAD_VALUE;
+ }
+ const uint8_t* internalBuffer = parcel->get()->data();
+ memcpy(buffer, internalBuffer + start, len);
+ return STATUS_OK;
+}
+
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len) {
+ status_t status = parcel->get()->setDataSize(len);
+ if (status != ::android::OK) {
+ return PruneStatusT(status);
+ }
+ parcel->get()->setDataPosition(0);
+
+ void* raw = parcel->get()->writeInplace(len);
+ if (raw == nullptr) {
+ return STATUS_NO_MEMORY;
+ }
+ memcpy(raw, buffer, len);
+ return STATUS_OK;
+}
+
// @END
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index a8ae441..8ed91a5 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -20,6 +20,7 @@
#include <android-base/logging.h>
using ::android::status_t;
+using ::android::statusToString;
using ::android::binder::Status;
AStatus* AStatus_newOk() {
@@ -126,7 +127,7 @@
return STATUS_UNKNOWN_ERROR;
default:
- LOG(WARNING) << __func__ << ": Unknown status_t (" << status
+ LOG(WARNING) << __func__ << ": Unknown status_t (" << statusToString(status)
<< ") pruned into STATUS_UNKNOWN_ERROR";
return STATUS_UNKNOWN_ERROR;
}
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index ede4873..8ee396e 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -71,9 +71,12 @@
srcs: ["libbinder_ndk_unit_test.cpp"],
static_libs: [
"IBinderNdkUnitTest-cpp",
- "IBinderNdkUnitTest-ndk_platform",
+ "IBinderNdkUnitTest-ndk",
],
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -85,8 +88,8 @@
],
static_libs: [
"IBinderVendorDoubleLoadTest-cpp",
- "IBinderVendorDoubleLoadTest-ndk_platform",
- "libbinder_aidl_test_stub-ndk_platform",
+ "IBinderVendorDoubleLoadTest-ndk",
+ "libbinder_aidl_test_stub-ndk",
],
// critical that libbinder/libbinder_ndk are shared for VTS
shared_libs: [
@@ -115,4 +118,12 @@
"IBinderNdkUnitTest.aidl",
"IEmpty.aidl",
],
+ backend: {
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ apps_enabled: false,
+ },
+ },
}
diff --git a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
index ecbd649..a626d39 100644
--- a/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
@@ -21,6 +21,7 @@
import IEmpty;
+@SensitiveData
interface IBinderNdkUnitTest {
int repeatInt(int a);
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 62db3cf..357b454 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,6 +39,7 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
+#include <thread>
#include "android/binder_ibinder.h"
using namespace android;
@@ -223,6 +224,17 @@
return true;
}
+TEST(NdkBinder, DetectDoubleOwn) {
+ auto badService = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ EXPECT_DEATH(std::shared_ptr<MyBinderNdkUnitTest>(badService.get()),
+ "Is this object double-owned?");
+}
+
+TEST(NdkBinder, DetectNoSharedRefBaseCreated) {
+ EXPECT_DEATH(std::make_shared<MyBinderNdkUnitTest>(),
+ "SharedRefBase: no ref created during lifetime");
+}
+
TEST(NdkBinder, GetServiceThatDoesntExist) {
sp<IFoo> foo = IFoo::getService("asdfghkl;");
EXPECT_EQ(nullptr, foo.get());
@@ -270,6 +282,27 @@
EXPECT_EQ(2, out);
}
+TEST(NdkBinder, GetTestServiceStressTest) {
+ // libbinder has some complicated logic to make sure only one instance of
+ // ABpBinder is associated with each binder.
+
+ constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumCalls = 1000;
+ std::vector<std::thread> threads;
+
+ for (size_t i = 0; i < kNumThreads; i++) {
+ threads.push_back(std::thread([&]() {
+ for (size_t j = 0; j < kNumCalls; j++) {
+ auto binder =
+ ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+ }
+ }));
+ }
+
+ for (auto& thread : threads) thread.join();
+}
+
void defaultInstanceCounter(const char* instance, void* context) {
if (strcmp(instance, "default") == 0) {
++*(size_t*)(context);
@@ -362,9 +395,16 @@
<< "Service failed to shut down.";
}
+struct DeathRecipientCookie {
+ std::function<void(void)>*onDeath, *onUnlink;
+};
void LambdaOnDeath(void* cookie) {
- auto onDeath = static_cast<std::function<void(void)>*>(cookie);
- (*onDeath)();
+ auto funcs = static_cast<DeathRecipientCookie*>(cookie);
+ (*funcs->onDeath)();
+};
+void LambdaOnUnlink(void* cookie) {
+ auto funcs = static_cast<DeathRecipientCookie*>(cookie);
+ (*funcs->onUnlink)();
};
TEST(NdkBinder, DeathRecipient) {
using namespace std::chrono_literals;
@@ -376,26 +416,46 @@
std::mutex deathMutex;
std::condition_variable deathCv;
- bool deathRecieved = false;
+ bool deathReceived = false;
std::function<void(void)> onDeath = [&] {
std::cerr << "Binder died (as requested)." << std::endl;
- deathRecieved = true;
+ deathReceived = true;
deathCv.notify_one();
};
- AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+ std::mutex unlinkMutex;
+ std::condition_variable unlinkCv;
+ bool unlinkReceived = false;
+ bool wasDeathReceivedFirst = false;
- EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+ std::function<void(void)> onUnlink = [&] {
+ std::cerr << "Binder unlinked (as requested)." << std::endl;
+ wasDeathReceivedFirst = deathReceived;
+ unlinkReceived = true;
+ unlinkCv.notify_one();
+ };
+
+ DeathRecipientCookie cookie = {&onDeath, &onUnlink};
+
+ AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+ AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink);
+
+ EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&cookie)));
// the binder driver should return this if the service dies during the transaction
EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
foo = nullptr;
- std::unique_lock<std::mutex> lock(deathMutex);
- EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
- EXPECT_TRUE(deathRecieved);
+ std::unique_lock<std::mutex> lockDeath(deathMutex);
+ EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; }));
+ EXPECT_TRUE(deathReceived);
+
+ std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
+ EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; }));
+ EXPECT_TRUE(unlinkReceived);
+ EXPECT_TRUE(wasDeathReceivedFirst);
AIBinder_DeathRecipient_delete(recipient);
AIBinder_decStrong(binder);
@@ -445,6 +505,31 @@
}
};
+TEST(NdkBinder, SetInheritRt) {
+ // functional test in binderLibTest
+ sp<IFoo> foo = sp<MyTestFoo>::make();
+ AIBinder* binder = foo->getBinder();
+
+ // does not abort
+ AIBinder_setInheritRt(binder, true);
+ AIBinder_setInheritRt(binder, false);
+ AIBinder_setInheritRt(binder, true);
+
+ AIBinder_decStrong(binder);
+}
+
+TEST(NdkBinder, SetInheritRtNonLocal) {
+ AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+ ASSERT_NE(binder, nullptr);
+
+ ASSERT_TRUE(AIBinder_isRemote(binder));
+
+ EXPECT_DEATH(AIBinder_setInheritRt(binder, true), "");
+ EXPECT_DEATH(AIBinder_setInheritRt(binder, false), "");
+
+ AIBinder_decStrong(binder);
+}
+
TEST(NdkBinder, AddNullService) {
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, AServiceManager_addService(nullptr, "any-service-name"));
}
@@ -667,6 +752,29 @@
ASSERT_STREQ(IFoo::kIFooDescriptor, AIBinder_Class_getDescriptor(IFoo::kClass));
}
+static void addOne(int* to) {
+ if (!to) return;
+ ++(*to);
+}
+struct FakeResource : public ndk::impl::ScopedAResource<int*, addOne, nullptr> {
+ explicit FakeResource(int* a) : ScopedAResource(a) {}
+};
+
+TEST(NdkBinder_ScopedAResource, GetDelete) {
+ int deleteCount = 0;
+ { FakeResource resource(&deleteCount); }
+ EXPECT_EQ(deleteCount, 1);
+}
+
+TEST(NdkBinder_ScopedAResource, Release) {
+ int deleteCount = 0;
+ {
+ FakeResource resource(&deleteCount);
+ (void)resource.release();
+ }
+ EXPECT_EQ(deleteCount, 0);
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/run_rpc_tests.sh b/libs/binder/run_rpc_tests.sh
new file mode 100755
index 0000000..7ba682d
--- /dev/null
+++ b/libs/binder/run_rpc_tests.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+set -ex
+
+if [ $# -eq 0 ]; then
+ :
+elif [ $# -eq 1 ] && [[ "$1" =~ ^host|device$ ]]; then
+ :
+else
+ echo "usage: $0 [device|host]"
+ false
+fi
+
+# Script maintained for RPC development, while it is active, to quickly run
+# tests. Generally, to match VTS/presubmit behavior, 'atest' should be used.
+
+function dtest () { adb shell /data/nativetest64/$1/$@; }
+function hbench () { $AT/out/host/linux-x86/benchmarktest/$1/$@; }
+function hfuzz () { time $ANDROID_HOST_OUT/fuzz/x86_64/$1/$@; }
+function htest () { time $ANDROID_BUILD_TOP/out/host/linux-x86/nativetest/$1/$@; }
+function pdtest () { adb wait-for-device && adb shell mkdir -p /data/nativetest64/$1 && adb push $OUT/data/nativetest64/$1/$1 /data/nativetest64/$1/$1 && dtest $@; }
+function dbench () { adb shell /data/benchmarktest64/$1/$@; }
+function pdbench () { adb wait-for-device && adb shell mkdir -p /data/benchmarktest64/$1 && adb push $OUT/data/benchmarktest64/$1/$1 /data/benchmarktest64/$1/$1 && dbench $@; }
+
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
+ binderRpcTest \
+ binder_rpc_fuzzer \
+ binder_parcel_fuzzer \
+ binderLibTest \
+ binderRpcBenchmark
+
+if ! [ "$1" = "device" ]; then
+ htest binderRpcTest
+ hbench binderRpcBenchmark
+ hfuzz binder_rpc_fuzzer -max_total_time=30
+ hfuzz binder_parcel_fuzzer -max_total_time=30
+fi
+
+if ! [ "$1" = "host" ]; then
+ pdtest binderRpcTest
+ pdtest binderLibTest
+ pdbench binderRpcBenchmark
+fi
+
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 49d3401..355b3b4 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -17,17 +17,46 @@
rustlibs: [
"liblibc",
"libbinder_ndk_sys",
+ "libdowncast_rs",
],
host_supported: true,
+ vendor_available: true,
target: {
darwin: {
enabled: false,
- }
+ },
},
apex_available: [
"//apex_available:platform",
+ "com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "Tiramisu",
+}
+
+rust_library {
+ name: "libbinder_tokio_rs",
+ crate_name: "binder_tokio",
+ srcs: ["binder_tokio/lib.rs"],
+ rustlibs: [
+ "libbinder_rs",
+ "libtokio",
+ ],
+ host_supported: true,
+ vendor_available: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.compos",
+ "com.android.uwb",
+ "com.android.virt",
+ ],
+ min_sdk_version: "Tiramisu",
}
rust_library {
@@ -41,15 +70,19 @@
"libbinder_ndk",
],
host_supported: true,
+ vendor_available: true,
target: {
darwin: {
enabled: false,
- }
+ },
},
apex_available: [
"//apex_available:platform",
+ "com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "Tiramisu",
lints: "none",
clippy_lints: "none",
}
@@ -62,45 +95,69 @@
bindgen_flags: [
// Unfortunately the only way to specify the rust_non_exhaustive enum
// style for a type is to make it the default
- "--default-enum-style", "rust_non_exhaustive",
+ "--default-enum-style",
+ "rust_non_exhaustive",
// and then specify constified enums for the enums we don't want
// rustified
- "--constified-enum", "android::c_interface::consts::.*",
+ "--constified-enum",
+ "android::c_interface::consts::.*",
- "--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", ".*",
+ "--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",
],
host_supported: true,
+ vendor_available: true,
// Currently necessary for host builds
// TODO(b/31559095): bionic on host should define this
target: {
- host: {
- cflags: [
- "-D__INTRODUCED_IN(n)=",
- "-D__assert(a,b,c)=",
- // We want all the APIs to be available on the host.
- "-D__ANDROID_API__=10000",
- ],
- },
darwin: {
enabled: false,
},
},
apex_available: [
"//apex_available:platform",
+ "com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "Tiramisu",
+}
+
+// TODO(b/184872979): remove once the Rust API is created.
+rust_bindgen {
+ name: "libbinder_rpc_unstable_bindgen",
+ wrapper_src: ":libbinder_rpc_unstable_header",
+ crate_name: "binder_rpc_unstable_bindgen",
+ source_stem: "bindings",
+ shared_libs: [
+ "libutils",
+ ],
+ apex_available: [
+ "com.android.compos",
+ "com.android.uwb",
+ "com.android.virt",
+ ],
+ min_sdk_version: "Tiramisu",
}
rust_test {
@@ -115,5 +172,26 @@
rustlibs: [
"liblibc",
"libbinder_ndk_sys",
+ "libdowncast_rs",
],
}
+
+rust_test {
+ name: "libbinder_ndk_bindgen_test",
+ srcs: [":libbinder_ndk_bindgen"],
+ crate_name: "binder_ndk_bindgen",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
+
+rust_test {
+ name: "libbinder_rpc_unstable_bindgen_test",
+ srcs: [":libbinder_rpc_unstable_bindgen"],
+ crate_name: "binder_rpc_unstable_bindgen",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
new file mode 100644
index 0000000..9dcef42
--- /dev/null
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+//! This crate lets you use the Tokio `spawn_blocking` pool with AIDL in async
+//! Rust code.
+//!
+//! This crate works by defining a type [`Tokio`], which you can use as the
+//! generic parameter in the async version of the trait generated by the AIDL
+//! compiler.
+//! ```text
+//! use binder_tokio::Tokio;
+//!
+//! binder::get_interface::<dyn SomeAsyncInterface<Tokio>>("...").
+//! ```
+//!
+//! [`Tokio`]: crate::Tokio
+
+use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
+use binder::binder_impl::BinderAsyncRuntime;
+use std::future::Future;
+
+/// Retrieve an existing service for a particular interface, sleeping for a few
+/// seconds if it doesn't yet exist.
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+ if binder::is_handling_transaction() {
+ // See comment in the BinderAsyncPool impl.
+ return binder::get_interface::<T>(name);
+ }
+
+ let name = name.to_string();
+ let res = tokio::task::spawn_blocking(move || {
+ binder::get_interface::<T>(&name)
+ }).await;
+
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match res {
+ Ok(Ok(service)) => Ok(service),
+ Ok(Err(err)) => Err(err),
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+ }
+}
+
+/// Retrieve an existing service for a particular interface, or start it if it
+/// is configured as a dynamic service and isn't yet started.
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+ if binder::is_handling_transaction() {
+ // See comment in the BinderAsyncPool impl.
+ return binder::wait_for_interface::<T>(name);
+ }
+
+ let name = name.to_string();
+ let res = tokio::task::spawn_blocking(move || {
+ binder::wait_for_interface::<T>(&name)
+ }).await;
+
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match res {
+ Ok(Ok(service)) => Ok(service),
+ Ok(Err(err)) => Err(err),
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+ }
+}
+
+/// Use the Tokio `spawn_blocking` pool with AIDL.
+pub enum Tokio {}
+
+impl BinderAsyncPool for Tokio {
+ fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+ where
+ F1: FnOnce() -> A,
+ F2: FnOnce(A) -> Fut,
+ Fut: Future<Output = Result<B, E>>,
+ F1: Send + 'static,
+ F2: Send + 'a,
+ Fut: Send + 'a,
+ A: Send + 'static,
+ B: Send + 'a,
+ E: From<crate::StatusCode>,
+ {
+ if binder::is_handling_transaction() {
+ // We are currently on the thread pool for a binder server, so we should execute the
+ // transaction on the current thread so that the binder kernel driver is able to apply
+ // its deadlock prevention strategy to the sub-call.
+ //
+ // This shouldn't cause issues with blocking the thread as only one task will run in a
+ // call to `block_on`, so there aren't other tasks to block.
+ let result = spawn_me();
+ Box::pin(after_spawn(result))
+ } else {
+ let handle = tokio::task::spawn_blocking(spawn_me);
+ Box::pin(async move {
+ // The `is_panic` branch is not actually reachable in Android as we compile
+ // with `panic = abort`.
+ match handle.await {
+ Ok(res) => after_spawn(res).await,
+ Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+ Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION.into()),
+ Err(_) => Err(StatusCode::UNKNOWN_ERROR.into()),
+ }
+ })
+ }
+ }
+}
+
+/// Wrapper around Tokio runtime types for providing a runtime to a binder server.
+pub struct TokioRuntime<R>(pub R);
+
+impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Runtime> {
+ fn block_on<F: Future>(&self, future: F) -> F::Output {
+ self.0.block_on(future)
+ }
+}
+
+impl BinderAsyncRuntime for TokioRuntime<std::sync::Arc<tokio::runtime::Runtime>> {
+ fn block_on<F: Future>(&self, future: F) -> F::Output {
+ self.0.block_on(future)
+ }
+}
+
+impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Handle> {
+ fn block_on<F: Future>(&self, future: F) -> F::Output {
+ self.0.block_on(future)
+ }
+}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 695a83e..5d6206d 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,14 +17,16 @@
//! Trait definitions for binder objects
use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::{Parcel, BorrowedParcel};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
use std::borrow::Borrow;
use std::cmp::Ordering;
+use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fmt;
+use std::fs::File;
use std::marker::PhantomData;
use std::ops::Deref;
use std::os::raw::c_char;
@@ -49,11 +51,48 @@
/// interfaces) must implement this trait.
///
/// This is equivalent `IInterface` in C++.
-pub trait Interface: Send {
+pub trait Interface: Send + Sync {
/// Convert this binder object into a generic [`SpIBinder`] reference.
fn as_binder(&self) -> SpIBinder {
panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
}
+
+ /// Dump transaction handler for this Binder object.
+ ///
+ /// This handler is a no-op by default and should be implemented for each
+ /// Binder service struct that wishes to respond to dump transactions.
+ fn dump(&self, _file: &File, _args: &[&CStr]) -> Result<()> {
+ Ok(())
+ }
+}
+
+/// Implemented by sync interfaces to specify what the associated async interface is.
+/// Generic to handle the fact that async interfaces are generic over a thread pool.
+///
+/// The binder in any object implementing this trait should be compatible with the
+/// `Target` associated type, and using `FromIBinder` to convert it to the target
+/// should not fail.
+pub trait ToAsyncInterface<P>
+where
+ Self: Interface,
+ Self::Target: FromIBinder,
+{
+ /// The async interface associated with this sync interface.
+ type Target: ?Sized;
+}
+
+/// Implemented by async interfaces to specify what the associated sync interface is.
+///
+/// The binder in any object implementing this trait should be compatible with the
+/// `Target` associated type, and using `FromIBinder` to convert it to the target
+/// should not fail.
+pub trait ToSyncInterface
+where
+ Self: Interface,
+ Self::Target: FromIBinder,
+{
+ /// The sync interface associated with this async interface.
+ type Target: ?Sized;
}
/// Interface stability promise
@@ -61,6 +100,7 @@
/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
/// makes no stability guarantees ([`Local`]). [`Local`] is
/// currently the default stability.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Stability {
/// Default stability, visible to other modules in the same compilation
/// context (e.g. modules on system.img)
@@ -76,6 +116,28 @@
}
}
+impl From<Stability> for i32 {
+ fn from(stability: Stability) -> i32 {
+ use Stability::*;
+ match stability {
+ Local => 0,
+ Vintf => 1,
+ }
+ }
+}
+
+impl TryFrom<i32> for Stability {
+ type Error = StatusCode;
+ fn try_from(stability: i32) -> Result<Stability> {
+ use Stability::*;
+ match stability {
+ 0 => Ok(Local),
+ 1 => Ok(Vintf),
+ _ => Err(StatusCode::BAD_VALUE)
+ }
+ }
+}
+
/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
@@ -96,7 +158,11 @@
/// Handle and reply to a request to invoke a transaction on this object.
///
/// `reply` may be [`None`] if the sender does not expect a reply.
- fn on_transact(&self, code: TransactionCode, data: &Parcel, reply: &mut Parcel) -> Result<()>;
+ fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
+
+ /// Handle a request to invoke the dump transaction on this
+ /// object.
+ fn on_dump(&self, file: &File, args: &[&CStr]) -> Result<()>;
/// Retrieve the class of this remote object.
///
@@ -126,10 +192,8 @@
/// Is this object still alive?
fn is_binder_alive(&self) -> bool;
- /// Send a ping transaction to this object
- fn ping_binder(&mut self) -> Result<()>;
-
/// Indicate that the service intends to receive caller security contexts.
+ #[cfg(not(android_vndk))]
fn set_requesting_sid(&mut self, enable: bool);
/// Dump this object to the given file handle
@@ -139,20 +203,46 @@
/// available.
fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
+ /// Create a Parcel that can be used with `submit_transact`.
+ fn prepare_transact(&self) -> Result<Parcel>;
+
/// Perform a generic operation with the object.
///
+ /// The provided [`Parcel`] must have been created by a call to
+ /// `prepare_transact` on the same binder.
+ ///
+ /// # Arguments
+ ///
+ /// * `code` - Transaction code for the operation.
+ /// * `data` - [`Parcel`] with input data.
+ /// * `flags` - Transaction flags, e.g. marking the transaction as
+ /// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)).
+ fn submit_transact(
+ &self,
+ code: TransactionCode,
+ data: Parcel,
+ flags: TransactionFlags,
+ ) -> Result<Parcel>;
+
+ /// Perform a generic operation with the object. This is a convenience
+ /// method that internally calls `prepare_transact` followed by
+ /// `submit_transact.
+ ///
/// # Arguments
/// * `code` - Transaction code for the operation
- /// * `data` - [`Parcel`] with input data
- /// * `reply` - Optional [`Parcel`] for reply data
/// * `flags` - Transaction flags, e.g. marking the transaction as
/// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
- fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+ /// * `input_callback` A callback for building the `Parcel`.
+ fn transact<F: FnOnce(BorrowedParcel<'_>) -> Result<()>>(
&self,
code: TransactionCode,
flags: TransactionFlags,
input_callback: F,
- ) -> Result<Parcel>;
+ ) -> Result<Parcel> {
+ let mut parcel = self.prepare_transact()?;
+ input_callback(parcel.borrowed())?;
+ self.submit_transact(code, parcel, flags)
+ }
}
/// Interface of binder local or remote objects.
@@ -177,6 +267,9 @@
/// The recipient will no longer be called if this object
/// dies.
fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
+
+ /// Send a ping transaction to this object
+ fn ping_binder(&mut self) -> Result<()>;
}
/// Opaque reference to the type of a Binder interface.
@@ -218,7 +311,7 @@
if class.is_null() {
panic!("Expected non-null class pointer from AIBinder_Class_define!");
}
- sys::AIBinder_Class_setOnDump(class, None);
+ sys::AIBinder_Class_setOnDump(class, Some(I::on_dump));
sys::AIBinder_Class_setHandleShellCommand(class, None);
class
};
@@ -273,6 +366,26 @@
pub fn downgrade(this: &Strong<I>) -> Weak<I> {
Weak::new(this)
}
+
+ /// Convert this synchronous binder handle into an asynchronous one.
+ pub fn into_async<P>(self) -> Strong<<I as ToAsyncInterface<P>>::Target>
+ where
+ I: ToAsyncInterface<P>,
+ {
+ // By implementing the ToAsyncInterface trait, it is guaranteed that the binder
+ // object is also valid for the target type.
+ FromIBinder::try_from(self.0.as_binder()).unwrap()
+ }
+
+ /// Convert this asynchronous binder handle into a synchronous one.
+ pub fn into_sync(self) -> Strong<<I as ToSyncInterface>::Target>
+ where
+ I: ToSyncInterface,
+ {
+ // By implementing the ToSyncInterface trait, it is guaranteed that the binder
+ // object is also valid for the target type.
+ FromIBinder::try_from(self.0.as_binder()).unwrap()
+ }
}
impl<I: FromIBinder + ?Sized> Clone for Strong<I> {
@@ -412,8 +525,8 @@
/// fn on_transact(
/// &self,
/// code: TransactionCode,
-/// data: &Parcel,
-/// reply: &mut Parcel,
+/// data: &BorrowedParcel,
+/// reply: &mut BorrowedParcel,
/// ) -> Result<()> {
/// // ...
/// }
@@ -423,13 +536,13 @@
/// ```
macro_rules! binder_fn_get_class {
($class:ty) => {
- binder_fn_get_class!($crate::InterfaceClass::new::<$class>());
+ binder_fn_get_class!($crate::binder_impl::InterfaceClass::new::<$class>());
};
($constructor:expr) => {
- fn get_class() -> $crate::InterfaceClass {
+ fn get_class() -> $crate::binder_impl::InterfaceClass {
static CLASS_INIT: std::sync::Once = std::sync::Once::new();
- static mut CLASS: Option<$crate::InterfaceClass> = None;
+ static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
CLASS_INIT.call_once(|| unsafe {
// Safety: This assignment is guarded by the `CLASS_INIT` `Once`
@@ -492,6 +605,16 @@
/// returned by `on_create` for this class. This function takes ownership of
/// the provided pointer and destroys it.
unsafe extern "C" fn on_destroy(object: *mut c_void);
+
+ /// Called to handle the `dump` transaction.
+ ///
+ /// # Safety
+ ///
+ /// Must be called with a non-null, valid pointer to a local `AIBinder` that
+ /// contains a `T` pointer in its user data. fd should be a non-owned file
+ /// descriptor, and args must be an array of null-terminated string
+ /// poiinters with length num_args.
+ unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t;
}
/// Interface for transforming a generic SpIBinder into a specific remote
@@ -562,6 +685,7 @@
pub struct BinderFeatures {
/// Indicates that the service intends to receive caller security contexts. This must be true
/// for `ThreadState::with_calling_sid` to work.
+ #[cfg(not(android_vndk))]
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
@@ -582,13 +706,13 @@
/// have the following type:
///
/// ```
-/// # use binder::{Interface, TransactionCode, Parcel};
+/// # use binder::{Interface, TransactionCode, BorrowedParcel};
/// # trait Placeholder {
/// fn on_transact(
/// service: &dyn Interface,
/// code: TransactionCode,
-/// data: &Parcel,
-/// reply: &mut Parcel,
+/// data: &BorrowedParcel,
+/// reply: &mut BorrowedParcel,
/// ) -> binder::Result<()>;
/// # }
/// ```
@@ -603,7 +727,7 @@
/// using the provided function, `on_transact`.
///
/// ```
-/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, Parcel};
+/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, BorrowedParcel};
///
/// pub trait IServiceManager: Interface {
/// // remote methods...
@@ -619,8 +743,8 @@
/// fn on_transact(
/// service: &dyn IServiceManager,
/// code: TransactionCode,
-/// data: &Parcel,
-/// reply: &mut Parcel,
+/// data: &BorrowedParcel,
+/// reply: &mut BorrowedParcel,
/// ) -> binder::Result<()> {
/// // ...
/// Ok(())
@@ -640,13 +764,15 @@
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident,
+ $(async: $async_interface:ident,)?
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
- stability: $crate::Stability::default(),
+ $(async: $async_interface,)?
+ stability: $crate::binder_impl::Stability::default(),
}
}
};
@@ -655,6 +781,7 @@
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident,
+ $(async: $async_interface:ident,)?
stability: $stability:expr,
}
} => {
@@ -662,6 +789,7 @@
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
+ $(async: $async_interface,)?
stability: $stability,
}
}
@@ -673,6 +801,7 @@
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
+ $(async: $async_interface:ident,)?
}
} => {
$crate::declare_binder_interface! {
@@ -681,7 +810,8 @@
proxy: $proxy {
$($fname: $fty = $finit),*
},
- stability: $crate::Stability::default(),
+ $(async: $async_interface,)?
+ stability: $crate::binder_impl::Stability::default(),
}
}
};
@@ -692,17 +822,19 @@
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
+ $(async: $async_interface:ident,)?
stability: $stability:expr,
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
- @doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")]
+ @doc[concat!("A binder [`Remotable`]($crate::binder_impl::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.")]
+ @doc[concat!("A binder [`Proxy`]($crate::binder_impl::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
proxy: $proxy {
$($fname: $fty = $finit),*
},
+ $(async: $async_interface,)?
stability: $stability,
}
}
@@ -718,6 +850,8 @@
$($fname:ident: $fty:ty = $finit:expr),*
},
+ $( async: $async_interface:ident, )?
+
stability: $stability:expr,
}
} => {
@@ -733,7 +867,7 @@
}
}
- impl $crate::Proxy for $proxy
+ impl $crate::binder_impl::Proxy for $proxy
where
$proxy: $interface,
{
@@ -741,7 +875,7 @@
$descriptor
}
- fn from_binder(mut binder: $crate::SpIBinder) -> $crate::Result<Self> {
+ fn from_binder(mut binder: $crate::SpIBinder) -> std::result::Result<Self, $crate::StatusCode> {
Ok(Self { binder, $($fname: $finit),* })
}
}
@@ -753,18 +887,19 @@
impl $native {
/// Create a new binder service.
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);
+ let mut binder = $crate::binder_impl::Binder::new_with_stability($native(Box::new(inner)), $stability);
+ #[cfg(not(android_vndk))]
+ $crate::binder_impl::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
$crate::Strong::new(Box::new(binder))
}
}
- impl $crate::Remotable for $native {
+ impl $crate::binder_impl::Remotable for $native {
fn get_descriptor() -> &'static str {
$descriptor
}
- fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> {
+ fn on_transact(&self, code: $crate::binder_impl::TransactionCode, data: &$crate::binder_impl::BorrowedParcel<'_>, reply: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
match $on_transact(&*self.0, code, data, reply) {
// The C++ backend converts UNEXPECTED_NULL into an exception
Err($crate::StatusCode::UNEXPECTED_NULL) => {
@@ -778,15 +913,19 @@
}
}
- fn get_class() -> $crate::InterfaceClass {
+ fn on_dump(&self, file: &std::fs::File, args: &[&std::ffi::CStr]) -> std::result::Result<(), $crate::StatusCode> {
+ self.0.dump(file, args)
+ }
+
+ fn get_class() -> $crate::binder_impl::InterfaceClass {
static CLASS_INIT: std::sync::Once = std::sync::Once::new();
- static mut CLASS: Option<$crate::InterfaceClass> = None;
+ static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
CLASS_INIT.call_once(|| unsafe {
// Safety: This assignment is guarded by the `CLASS_INIT` `Once`
// variable, and therefore is thread-safe, as it can only occur
// once.
- CLASS = Some($crate::InterfaceClass::new::<$crate::Binder<$native>>());
+ CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>());
});
unsafe {
// Safety: The `CLASS` variable can only be mutated once, above,
@@ -797,25 +936,25 @@
}
impl $crate::FromIBinder for dyn $interface {
- fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $interface>> {
- use $crate::AssociateClass;
+ fn try_from(mut ibinder: $crate::SpIBinder) -> std::result::Result<$crate::Strong<dyn $interface>, $crate::StatusCode> {
+ use $crate::binder_impl::AssociateClass;
let existing_class = ibinder.get_class();
if let Some(class) = existing_class {
- if class != <$native as $crate::Remotable>::get_class() &&
- class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
+ if class != <$native as $crate::binder_impl::Remotable>::get_class() &&
+ class.get_descriptor() == <$native as $crate::binder_impl::Remotable>::get_descriptor()
{
// The binder object's descriptor string matches what we
// expect. We still need to treat this local or already
// associated object as remote, because we can't cast it
// into a Rust service object without a matching class
// pointer.
- return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
}
- if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
- let service: $crate::Result<$crate::Binder<$native>> =
+ if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
+ let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
std::convert::TryFrom::try_from(ibinder.clone());
if let Ok(service) = service {
// We were able to associate with our expected class and
@@ -823,7 +962,7 @@
return Ok($crate::Strong::new(Box::new(service)));
} else {
// Service is remote
- return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
}
@@ -831,23 +970,23 @@
}
}
- impl $crate::parcel::Serialize for dyn $interface + '_
+ impl $crate::binder_impl::Serialize for dyn $interface + '_
where
dyn $interface: $crate::Interface
{
- fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
let binder = $crate::Interface::as_binder(self);
parcel.write(&binder)
}
}
- impl $crate::parcel::SerializeOption for dyn $interface + '_ {
- fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ impl $crate::binder_impl::SerializeOption for dyn $interface + '_ {
+ fn serialize_option(this: Option<&Self>, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
parcel.write(&this.map($crate::Interface::as_binder))
}
}
- impl std::fmt::Debug for dyn $interface {
+ impl std::fmt::Debug for dyn $interface + '_ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.pad(stringify!($interface))
}
@@ -861,6 +1000,81 @@
.expect(concat!("Error cloning interface ", stringify!($interface)))
}
}
+
+ $(
+ // Async interface trait implementations.
+ impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
+ fn try_from(mut ibinder: $crate::SpIBinder) -> std::result::Result<$crate::Strong<dyn $async_interface<P>>, $crate::StatusCode> {
+ use $crate::binder_impl::AssociateClass;
+
+ let existing_class = ibinder.get_class();
+ if let Some(class) = existing_class {
+ if class != <$native as $crate::binder_impl::Remotable>::get_class() &&
+ class.get_descriptor() == <$native as $crate::binder_impl::Remotable>::get_descriptor()
+ {
+ // The binder object's descriptor string matches what we
+ // expect. We still need to treat this local or already
+ // associated object as remote, because we can't cast it
+ // into a Rust service object without a matching class
+ // pointer.
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
+ }
+ }
+
+ if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
+ let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
+ std::convert::TryFrom::try_from(ibinder.clone());
+ if let Ok(service) = service {
+ // We were able to associate with our expected class and
+ // the service is local.
+ todo!()
+ //return Ok($crate::Strong::new(Box::new(service)));
+ } else {
+ // Service is remote
+ return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
+ }
+ }
+
+ Err($crate::StatusCode::BAD_TYPE.into())
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> $crate::binder_impl::Serialize for dyn $async_interface<P> + '_ {
+ fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
+ let binder = $crate::Interface::as_binder(self);
+ parcel.write(&binder)
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> $crate::binder_impl::SerializeOption for dyn $async_interface<P> + '_ {
+ fn serialize_option(this: Option<&Self>, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
+ parcel.write(&this.map($crate::Interface::as_binder))
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> std::fmt::Debug for dyn $async_interface<P> + '_ {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.pad(stringify!($async_interface))
+ }
+ }
+
+ /// Convert a &dyn $async_interface to Strong<dyn $async_interface>
+ impl<P: $crate::BinderAsyncPool> std::borrow::ToOwned for dyn $async_interface<P> {
+ type Owned = $crate::Strong<dyn $async_interface<P>>;
+ fn to_owned(&self) -> Self::Owned {
+ self.as_binder().into_interface()
+ .expect(concat!("Error cloning interface ", stringify!($async_interface)))
+ }
+ }
+
+ impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToAsyncInterface<P> for dyn $interface {
+ type Target = dyn $async_interface<P>;
+ }
+
+ impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToSyncInterface for dyn $async_interface<P> {
+ type Target = dyn $interface;
+ }
+ )?
};
}
@@ -870,39 +1084,48 @@
#[macro_export]
macro_rules! declare_binder_enum {
{
- $enum:ident : $backing:ty {
- $( $name:ident = $value:expr, )*
+ $( #[$attr:meta] )*
+ $enum:ident : [$backing:ty; $size:expr] {
+ $( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
}
} => {
+ $( #[$attr] )*
#[derive(Debug, Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
+ #[allow(missing_docs)]
pub struct $enum(pub $backing);
impl $enum {
- $( pub const $name: Self = Self($value); )*
+ $( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
+
+ #[inline(always)]
+ #[allow(missing_docs)]
+ pub const fn enum_values() -> [Self; $size] {
+ [$(Self::$name),*]
+ }
}
- impl $crate::parcel::Serialize for $enum {
- fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ impl $crate::binder_impl::Serialize for $enum {
+ fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
parcel.write(&self.0)
}
}
- impl $crate::parcel::SerializeArray for $enum {
- fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+ impl $crate::binder_impl::SerializeArray for $enum {
+ fn serialize_array(slice: &[Self], parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
- <$backing as binder::parcel::SerializeArray>::serialize_array(&v[..], parcel)
+ <$backing as $crate::binder_impl::SerializeArray>::serialize_array(&v[..], parcel)
}
}
- impl $crate::parcel::Deserialize for $enum {
- fn deserialize(parcel: &$crate::parcel::Parcel) -> $crate::Result<Self> {
+ impl $crate::binder_impl::Deserialize for $enum {
+ fn deserialize(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Self, $crate::StatusCode> {
parcel.read().map(Self)
}
}
- impl $crate::parcel::DeserializeArray for $enum {
- fn deserialize_array(parcel: &$crate::parcel::Parcel) -> $crate::Result<Option<Vec<Self>>> {
+ impl $crate::binder_impl::DeserializeArray for $enum {
+ fn deserialize_array(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Option<Vec<Self>>, $crate::StatusCode> {
let v: Option<Vec<$backing>> =
- <$backing as binder::parcel::DeserializeArray>::deserialize_array(parcel)?;
+ <$backing as $crate::binder_impl::DeserializeArray>::deserialize_array(parcel)?;
Ok(v.map(|v| v.into_iter().map(Self).collect()))
}
}
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
new file mode 100644
index 0000000..579f9f9
--- /dev/null
+++ b/libs/binder/rust/src/binder_async.rs
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+use std::future::Future;
+use std::pin::Pin;
+
+/// A type alias for a pinned, boxed future that lets you write shorter code without littering it
+/// with Pin and Send bounds.
+pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+
+/// A thread pool for running binder transactions.
+pub trait BinderAsyncPool {
+ /// This function should conceptually behave like this:
+ ///
+ /// ```text
+ /// let result = spawn_thread(|| spawn_me()).await;
+ /// return after_spawn(result).await;
+ /// ```
+ ///
+ /// If the spawning fails for some reason, the method may also skip the `after_spawn` closure
+ /// and immediately return an error.
+ ///
+ /// The only difference between different implementations should be which
+ /// `spawn_thread` method is used. For Tokio, it would be `tokio::task::spawn_blocking`.
+ ///
+ /// This method has the design it has because the only way to define a trait that
+ /// allows the return type of the spawn to be chosen by the caller is to return a
+ /// boxed `Future` trait object, and including `after_spawn` in the trait function
+ /// allows the caller to avoid double-boxing if they want to do anything to the value
+ /// returned from the spawned thread.
+ fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+ where
+ F1: FnOnce() -> A,
+ F2: FnOnce(A) -> Fut,
+ Fut: Future<Output = Result<B, E>>,
+ F1: Send + 'static,
+ F2: Send + 'a,
+ Fut: Send + 'a,
+ A: Send + 'static,
+ B: Send + 'a,
+ E: From<crate::StatusCode>;
+}
+
+/// A runtime for executing an async binder server.
+pub trait BinderAsyncRuntime {
+ /// Block on the provided future, running it to completion and returning its output.
+ fn block_on<F: Future>(&self, future: F) -> F::Output;
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 2694cba..dbfb1c2 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -50,8 +50,8 @@
//! fn on_transact(
//! service: &dyn ITest,
//! code: TransactionCode,
-//! _data: &Parcel,
-//! reply: &mut Parcel,
+//! _data: &BorrowedParcel,
+//! reply: &mut BorrowedParcel,
//! ) -> binder::Result<()> {
//! match code {
//! SpIBinder::FIRST_CALL_TRANSACTION => {
@@ -98,36 +98,53 @@
#[macro_use]
mod binder;
+mod binder_async;
mod error;
mod native;
+mod parcel;
mod state;
use binder_ndk_sys as sys;
-pub mod parcel;
-
-pub use crate::binder::{
- 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 binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
+pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
+pub use error::{ExceptionCode, Status, StatusCode};
+pub use native::{
+ add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
};
-pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
-pub use native::add_service;
-pub use native::Binder;
-pub use parcel::Parcel;
-pub use proxy::{get_interface, get_service};
-pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
+pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
+pub use proxy::{
+ get_declared_instances, get_interface, get_service, is_declared, wait_for_interface,
+ wait_for_service, DeathRecipient, SpIBinder, WpIBinder,
+};
pub use state::{ProcessState, ThreadState};
-/// The public API usable outside AIDL-generated interface crates.
-pub mod public_api {
- pub use super::parcel::ParcelFileDescriptor;
- pub use super::{add_service, get_interface};
- pub use super::{
- BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
- Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
- };
+/// Binder result containing a [`Status`] on error.
+pub type Result<T> = std::result::Result<T, Status>;
- /// Binder result containing a [`Status`] on error.
- pub type Result<T> = std::result::Result<T, Status>;
+/// Advanced Binder APIs needed internally by AIDL or when manually using Binder
+/// without AIDL.
+pub mod binder_impl {
+ pub use crate::binder::{
+ IBinderInternal, InterfaceClass, Remotable, Stability, ToAsyncInterface, ToSyncInterface,
+ TransactionCode, TransactionFlags, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
+ FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
+ };
+ pub use crate::binder_async::BinderAsyncRuntime;
+ pub use crate::error::status_t;
+ pub use crate::native::Binder;
+ pub use crate::parcel::{
+ BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel,
+ ParcelableMetadata, Serialize, SerializeArray, SerializeOption, NON_NULL_PARCELABLE_FLAG,
+ NULL_PARCELABLE_FLAG,
+ };
+ pub use crate::proxy::{AssociateClass, Proxy};
+}
+
+/// Unstable, in-development API that only allowlisted clients are allowed to use.
+#[doc(hidden)]
+pub mod unstable_api {
+ pub use crate::binder::AsNative;
+ pub use crate::proxy::unstable_api::new_spibinder;
+ pub use crate::sys::AIBinder;
}
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 3920129..b7c7ae4 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,16 +14,22 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, Stability, 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::parcel::{BorrowedParcel, Serialize};
use crate::proxy::SpIBinder;
use crate::sys;
use std::convert::TryFrom;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
+use std::fs::File;
use std::mem::ManuallyDrop;
use std::ops::Deref;
+use std::os::raw::c_char;
+use std::os::unix::io::FromRawFd;
+use std::slice;
/// Rust wrapper around Binder remotable objects.
///
@@ -47,6 +53,25 @@
/// to how `Box<T>` is `Send` if `T` is `Send`.
unsafe impl<T: Remotable> Send for Binder<T> {}
+/// # Safety
+///
+/// A `Binder<T>` is a pair of unique owning pointers to two values:
+/// * a C++ ABBinder which is thread-safe, i.e. `Send + Sync`
+/// * a Rust object which implements `Remotable`; this trait requires `Send + Sync`
+///
+/// `ABBinder` contains an immutable `mUserData` pointer, which is actually a
+/// pointer to a boxed `T: Remotable`, which is `Sync`. `ABBinder` also contains
+/// a mutable pointer to its class, but mutation of this field is controlled by
+/// a mutex and it is only allowed to be set once, therefore we can concurrently
+/// access this field safely. `ABBinder` inherits from `BBinder`, which is also
+/// thread-safe. Thus `ABBinder` is thread-safe.
+///
+/// Both pointers are unique (never escape the `Binder<T>` object and are not copied)
+/// so we can essentially treat `Binder<T>` as a box-like containing the two objects;
+/// the box-like object inherits `Sync` from the two inner values, similarly
+/// to how `Box<T>` is `Sync` if `T` is `Sync`.
+unsafe impl<T: Remotable> Sync for Binder<T> {}
+
impl<T: Remotable> Binder<T> {
/// Create a new Binder remotable object with default stability
///
@@ -136,8 +161,8 @@
/// # fn on_transact(
/// # service: &dyn IBar,
/// # code: TransactionCode,
- /// # data: &Parcel,
- /// # reply: &mut Parcel,
+ /// # data: &BorrowedParcel,
+ /// # reply: &mut BorrowedParcel,
/// # ) -> binder::Result<()> {
/// # Ok(())
/// # }
@@ -187,7 +212,7 @@
/// Mark this binder object with local stability, which is vendor if we are
/// building for the VNDK and system otherwise.
- #[cfg(vendor_ndk)]
+ #[cfg(any(vendor_ndk, android_vndk))]
fn mark_local_stability(&mut self) {
unsafe {
// Safety: Self always contains a valid `AIBinder` pointer, so
@@ -198,7 +223,7 @@
/// Mark this binder object with local stability, which is vendor if we are
/// building for the VNDK and system otherwise.
- #[cfg(not(vendor_ndk))]
+ #[cfg(not(any(vendor_ndk, android_vndk)))]
fn mark_local_stability(&mut self) {
unsafe {
// Safety: Self always contains a valid `AIBinder` pointer, so
@@ -252,8 +277,8 @@
reply: *mut sys::AParcel,
) -> status_t {
let res = {
- let mut reply = Parcel::borrowed(reply).unwrap();
- let data = Parcel::borrowed(data as *mut sys::AParcel).unwrap();
+ let mut reply = BorrowedParcel::from_raw(reply).unwrap();
+ let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
let object = sys::AIBinder_getUserData(binder);
let binder: &T = &*(object as *const T);
binder.on_transact(code, &data, &mut reply)
@@ -289,6 +314,42 @@
// object created by Box.
args
}
+
+ /// Called to handle the `dump` transaction.
+ ///
+ /// # Safety
+ ///
+ /// Must be called with a non-null, valid pointer to a local `AIBinder` that
+ /// contains a `T` pointer in its user data. fd should be a non-owned file
+ /// descriptor, and args must be an array of null-terminated string
+ /// poiinters with length num_args.
+ unsafe extern "C" fn on_dump(
+ binder: *mut sys::AIBinder,
+ fd: i32,
+ args: *mut *const c_char,
+ num_args: u32,
+ ) -> status_t {
+ if fd < 0 {
+ return StatusCode::UNEXPECTED_NULL as status_t;
+ }
+ // We don't own this file, so we need to be careful not to drop it.
+ let file = ManuallyDrop::new(File::from_raw_fd(fd));
+
+ if args.is_null() {
+ return StatusCode::UNEXPECTED_NULL as status_t;
+ }
+ let args = slice::from_raw_parts(args, num_args as usize);
+ let args: Vec<_> = args.iter().map(|s| CStr::from_ptr(*s)).collect();
+
+ let object = sys::AIBinder_getUserData(binder);
+ let binder: &T = &*(object as *const T);
+ let res = binder.on_dump(&file, &args);
+
+ match res {
+ Ok(()) => 0,
+ Err(e) => e as status_t,
+ }
+ }
}
impl<T: Remotable> Drop for Binder<T> {
@@ -323,7 +384,7 @@
}
impl<B: Remotable> Serialize for Binder<B> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(Some(&self.as_binder()))
}
}
@@ -380,6 +441,8 @@
///
/// Registers the given binder object with the given identifier. If successful,
/// this service can then be retrieved using that identifier.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status = unsafe {
@@ -393,6 +456,43 @@
status_result(status)
}
+/// Register a dynamic service via the LazyServiceRegistrar.
+///
+/// Registers the given binder object with the given identifier. If successful,
+/// this service can then be retrieved using that identifier. The service process
+/// will be shut down once all registered services are no longer in use.
+///
+/// If any service in the process is registered as lazy, all should be, otherwise
+/// the process may be shut down while a service is in use.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
+pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
+ let instance = CString::new(identifier).unwrap();
+ let status = unsafe {
+ // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
+ // string pointers. Caller retains ownership of both
+ // pointers. `AServiceManager_registerLazyService` creates a new strong reference
+ // and copies the string, so both pointers need only be valid until the
+ // call returns.
+
+ sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
+ };
+ status_result(status)
+}
+
+/// Prevent a process which registers lazy services from being shut down even when none
+/// of the services is in use.
+///
+/// If persist is true then shut down will be blocked until this function is called again with
+/// persist false. If this is to be the initial state, call this function before calling
+/// register_lazy_service.
+pub fn force_lazy_services_persist(persist: bool) {
+ unsafe {
+ // Safety: No borrowing or transfer of ownership occurs here.
+ sys::AServiceManager_forceLazyServicesPersist(persist)
+ }
+}
+
/// Tests often create a base BBinder instance; so allowing the unit
/// type to be remotable translates nicely to Binder::new(()).
impl Remotable for () {
@@ -403,13 +503,26 @@
fn on_transact(
&self,
_code: TransactionCode,
- _data: &Parcel,
- _reply: &mut Parcel,
+ _data: &BorrowedParcel<'_>,
+ _reply: &mut BorrowedParcel<'_>,
) -> Result<()> {
Ok(())
}
+ fn on_dump(&self, _file: &File, _args: &[&CStr]) -> Result<()> {
+ Ok(())
+ }
+
binder_fn_get_class!(Binder::<Self>);
}
impl Interface for () {}
+
+/// Determine whether the current thread is currently executing an incoming
+/// transaction.
+pub fn is_handling_transaction() -> bool {
+ unsafe {
+ // Safety: This method is always safe to call.
+ sys::AIBinder_isHandlingTransaction()
+ }
+}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 6c34824..256fa8b 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -21,18 +21,22 @@
use crate::proxy::SpIBinder;
use crate::sys;
-use std::cell::RefCell;
use std::convert::TryInto;
+use std::marker::PhantomData;
use std::mem::ManuallyDrop;
-use std::ptr;
+use std::ptr::{self, NonNull};
+use std::fmt;
mod file_descriptor;
mod parcelable;
+mod parcelable_holder;
pub use self::file_descriptor::ParcelFileDescriptor;
pub use self::parcelable::{
Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+ Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
};
+pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
/// Container for a message (data and object references) that can be sent
/// through Binder.
@@ -41,40 +45,42 @@
/// other side of the IPC, and references to live Binder objects that will
/// result in the other side receiving a proxy Binder connected with the
/// original Binder in the Parcel.
-pub enum Parcel {
- /// Owned parcel pointer
- Owned(*mut sys::AParcel),
- /// Borrowed parcel pointer (will not be destroyed on drop)
- Borrowed(*mut sys::AParcel),
+///
+/// This type represents a parcel that is owned by Rust code.
+#[repr(transparent)]
+pub struct Parcel {
+ ptr: NonNull<sys::AParcel>,
}
/// # Safety
///
-/// The `Parcel` constructors guarantee that a `Parcel` object will always
-/// contain a valid pointer to an `AParcel`.
-unsafe impl AsNative<sys::AParcel> for Parcel {
- fn as_native(&self) -> *const sys::AParcel {
- match *self {
- Self::Owned(x) | Self::Borrowed(x) => x,
- }
- }
+/// This type guarantees that it owns the AParcel and that all access to
+/// the AParcel happens through the Parcel, so it is ok to send across
+/// threads.
+unsafe impl Send for Parcel {}
- fn as_native_mut(&mut self) -> *mut sys::AParcel {
- match *self {
- Self::Owned(x) | Self::Borrowed(x) => x,
- }
- }
+/// Container for a message (data and object references) that can be sent
+/// through Binder.
+///
+/// This object is a borrowed variant of [`Parcel`]. It is a separate type from
+/// `&mut Parcel` because it is not valid to `mem::swap` two parcels.
+#[repr(transparent)]
+pub struct BorrowedParcel<'a> {
+ ptr: NonNull<sys::AParcel>,
+ _lifetime: PhantomData<&'a mut Parcel>,
}
impl Parcel {
- /// Create a borrowed reference to a parcel object from a raw pointer.
- ///
- /// # Safety
- ///
- /// This constructor is safe if the raw pointer parameter is either null
- /// (resulting in `None`), or a valid pointer to an `AParcel` object.
- pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
- ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
+ /// Create a new empty `Parcel`.
+ pub fn new() -> Parcel {
+ let ptr = unsafe {
+ // Safety: If `AParcel_create` succeeds, it always returns
+ // a valid pointer. If it fails, the process will crash.
+ sys::AParcel_create()
+ };
+ Self {
+ ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
+ }
}
/// Create an owned reference to a parcel object from a raw pointer.
@@ -85,21 +91,129 @@
/// (resulting in `None`), or a valid pointer to an `AParcel` object. The
/// parcel object must be owned by the caller prior to this call, as this
/// constructor takes ownership of the parcel and will destroy it on drop.
- pub(crate) unsafe fn owned(ptr: *mut sys::AParcel) -> Option<Parcel> {
- ptr.as_mut().map(|ptr| Self::Owned(ptr))
+ ///
+ /// Additionally, the caller must guarantee that it is valid to take
+ /// ownership of the AParcel object. All future access to the AParcel
+ /// must happen through this `Parcel`.
+ ///
+ /// Because `Parcel` implements `Send`, the pointer must never point to any
+ /// thread-local data, e.g., a variable on the stack, either directly or
+ /// indirectly.
+ pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<Parcel> {
+ NonNull::new(ptr).map(|ptr| Self { ptr })
}
- /// Consume the parcel, transferring ownership to the caller if the parcel
- /// was owned.
- pub(crate) fn into_raw(mut self) -> *mut sys::AParcel {
- let ptr = self.as_native_mut();
+ /// Consume the parcel, transferring ownership to the caller.
+ pub(crate) fn into_raw(self) -> *mut sys::AParcel {
+ let ptr = self.ptr.as_ptr();
let _ = ManuallyDrop::new(self);
ptr
}
+
+ /// Get a borrowed view into the contents of this `Parcel`.
+ pub fn borrowed(&mut self) -> BorrowedParcel<'_> {
+ // Safety: The raw pointer is a valid pointer to an AParcel, and the
+ // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+ // borrow checker will ensure that the `AParcel` can only be accessed
+ // via the `BorrowParcel` until it goes out of scope.
+ BorrowedParcel {
+ ptr: self.ptr,
+ _lifetime: PhantomData,
+ }
+ }
+
+ /// Get an immutable borrowed view into the contents of this `Parcel`.
+ pub fn borrowed_ref(&self) -> &BorrowedParcel<'_> {
+ // Safety: Parcel and BorrowedParcel are both represented in the same
+ // way as a NonNull<sys::AParcel> due to their use of repr(transparent),
+ // so casting references as done here is valid.
+ unsafe {
+ &*(self as *const Parcel as *const BorrowedParcel<'_>)
+ }
+ }
+}
+
+impl Default for Parcel {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Clone for Parcel {
+ fn clone(&self) -> Self {
+ let mut new_parcel = Self::new();
+ new_parcel
+ .borrowed()
+ .append_all_from(self.borrowed_ref())
+ .expect("Failed to append from Parcel");
+ new_parcel
+ }
+}
+
+impl<'a> BorrowedParcel<'a> {
+ /// Create a borrowed reference to a parcel object from a raw pointer.
+ ///
+ /// # Safety
+ ///
+ /// This constructor is safe if the raw pointer parameter is either null
+ /// (resulting in `None`), or a valid pointer to an `AParcel` object.
+ ///
+ /// Since the raw pointer is not restricted by any lifetime, the lifetime on
+ /// the returned `BorrowedParcel` object can be chosen arbitrarily by the
+ /// caller. The caller must ensure it is valid to mutably borrow the AParcel
+ /// for the duration of the lifetime that the caller chooses. Note that
+ /// since this is a mutable borrow, it must have exclusive access to the
+ /// AParcel for the duration of the borrow.
+ pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
+ Some(Self {
+ ptr: NonNull::new(ptr)?,
+ _lifetime: PhantomData,
+ })
+ }
+
+ /// Get a sub-reference to this reference to the parcel.
+ pub fn reborrow(&mut self) -> BorrowedParcel<'_> {
+ // Safety: The raw pointer is a valid pointer to an AParcel, and the
+ // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+ // borrow checker will ensure that the `AParcel` can only be accessed
+ // via the `BorrowParcel` until it goes out of scope.
+ BorrowedParcel {
+ ptr: self.ptr,
+ _lifetime: PhantomData,
+ }
+ }
+}
+
+/// # Safety
+///
+/// The `Parcel` constructors guarantee that a `Parcel` object will always
+/// contain a valid pointer to an `AParcel`.
+unsafe impl AsNative<sys::AParcel> for Parcel {
+ fn as_native(&self) -> *const sys::AParcel {
+ self.ptr.as_ptr()
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AParcel {
+ self.ptr.as_ptr()
+ }
+}
+
+/// # Safety
+///
+/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object
+/// will always contain a valid pointer to an `AParcel`.
+unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
+ fn as_native(&self) -> *const sys::AParcel {
+ self.ptr.as_ptr()
+ }
+
+ fn as_native_mut(&mut self) -> *mut sys::AParcel {
+ self.ptr.as_ptr()
+ }
}
// Data serialization methods
-impl Parcel {
+impl<'a> BorrowedParcel<'a> {
/// Data written to parcelable is zero'd before being deleted or reallocated.
pub fn mark_sensitive(&mut self) {
unsafe {
@@ -108,12 +222,12 @@
}
}
- /// Write a type that implements [`Serialize`] to the `Parcel`.
+ /// Write a type that implements [`Serialize`] to the parcel.
pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
parcelable.serialize(self)
}
- /// Writes the length of a slice to the `Parcel`.
+ /// Writes the length of a slice to the parcel.
///
/// This is used in AIDL-generated client side code to indicate the
/// allocated space for an output array parameter.
@@ -126,7 +240,7 @@
}
}
- /// Perform a series of writes to the `Parcel`, prepended with the length
+ /// Perform a series of writes to the parcel, prepended with the length
/// (in bytes) of the written data.
///
/// The length `0i32` will be written to the parcel first, followed by the
@@ -140,7 +254,7 @@
///
/// ```
/// # use binder::{Binder, Interface, Parcel};
- /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+ /// # let mut parcel = Parcel::new();
/// parcel.sized_write(|subparcel| {
/// subparcel.write(&1u32)?;
/// subparcel.write(&2u32)?;
@@ -154,14 +268,14 @@
/// [16i32, 1u32, 2u32, 3u32]
/// ```
pub fn sized_write<F>(&mut self, f: F) -> Result<()>
- where for<'a>
- F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+ where
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
{
let start = self.get_data_position();
self.write(&0i32)?;
{
- let subparcel = WritableSubParcel(RefCell::new(self));
- f(&subparcel)?;
+ let mut subparcel = WritableSubParcel(self.reborrow());
+ f(&mut subparcel)?;
}
let end = self.get_data_position();
unsafe {
@@ -178,17 +292,23 @@
/// Returns the current position in the parcel data.
pub fn get_data_position(&self) -> i32 {
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
- // and this call is otherwise safe.
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
sys::AParcel_getDataPosition(self.as_native())
}
}
+ /// Returns the total size of the parcel.
+ pub fn get_data_size(&self) -> i32 {
+ unsafe {
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
+ sys::AParcel_getDataSize(self.as_native())
+ }
+ }
+
/// Move the current read/write position in the parcel.
///
- /// The new position must be a position previously returned by
- /// `self.get_data_position()`.
- ///
/// # Safety
///
/// This method is safe if `pos` is less than the current size of the parcel
@@ -199,28 +319,213 @@
pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
}
+
+ /// Append a subset of another parcel.
+ ///
+ /// This appends `size` bytes of data from `other` starting at offset
+ /// `start` to the current parcel, or returns an error if not possible.
+ pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ let status = unsafe {
+ // Safety: `Parcel::appendFrom` from C++ checks that `start`
+ // and `size` are in bounds, and returns an error otherwise.
+ // Both `self` and `other` always contain valid pointers.
+ sys::AParcel_appendFrom(
+ other.as_native(),
+ self.as_native_mut(),
+ start,
+ size,
+ )
+ };
+ status_result(status)
+ }
+
+ /// Append the contents of another parcel.
+ pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
+ // `AParcel`, and this call is otherwise safe.
+ let size = unsafe { sys::AParcel_getDataSize(other.as_native()) };
+ self.append_from(other, 0, size)
+ }
}
-/// A segment of a writable parcel, used for [`Parcel::sized_write`].
-pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+/// A segment of a writable parcel, used for [`BorrowedParcel::sized_write`].
+pub struct WritableSubParcel<'a>(BorrowedParcel<'a>);
impl<'a> WritableSubParcel<'a> {
/// Write a type that implements [`Serialize`] to the sub-parcel.
- pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
- parcelable.serialize(&mut *self.0.borrow_mut())
+ pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+ parcelable.serialize(&mut self.0)
+ }
+}
+
+impl Parcel {
+ /// Data written to parcelable is zero'd before being deleted or reallocated.
+ pub fn mark_sensitive(&mut self) {
+ self.borrowed().mark_sensitive()
+ }
+
+ /// Write a type that implements [`Serialize`] to the parcel.
+ pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+ self.borrowed().write(parcelable)
+ }
+
+ /// Writes the length of a slice to the parcel.
+ ///
+ /// This is used in AIDL-generated client side code to indicate the
+ /// allocated space for an output array parameter.
+ pub fn write_slice_size<T>(&mut self, slice: Option<&[T]>) -> Result<()> {
+ self.borrowed().write_slice_size(slice)
+ }
+
+ /// Perform a series of writes to the parcel, prepended with the length
+ /// (in bytes) of the written data.
+ ///
+ /// The length `0i32` will be written to the parcel first, followed by the
+ /// writes performed by the callback. The initial length will then be
+ /// updated to the length of all data written by the callback, plus the
+ /// size of the length elemement itself (4 bytes).
+ ///
+ /// # Examples
+ ///
+ /// After the following call:
+ ///
+ /// ```
+ /// # use binder::{Binder, Interface, Parcel};
+ /// # let mut parcel = Parcel::new();
+ /// parcel.sized_write(|subparcel| {
+ /// subparcel.write(&1u32)?;
+ /// subparcel.write(&2u32)?;
+ /// subparcel.write(&3u32)
+ /// });
+ /// ```
+ ///
+ /// `parcel` will contain the following:
+ ///
+ /// ```ignore
+ /// [16i32, 1u32, 2u32, 3u32]
+ /// ```
+ pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+ where
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+ {
+ self.borrowed().sized_write(f)
+ }
+
+ /// Returns the current position in the parcel data.
+ pub fn get_data_position(&self) -> i32 {
+ self.borrowed_ref().get_data_position()
+ }
+
+ /// Returns the total size of the parcel.
+ pub fn get_data_size(&self) -> i32 {
+ self.borrowed_ref().get_data_size()
+ }
+
+ /// Move the current read/write position in the parcel.
+ ///
+ /// # Safety
+ ///
+ /// This method is safe if `pos` is less than the current size of the parcel
+ /// data buffer. Otherwise, we are relying on correct bounds checking in the
+ /// Parcel C++ code on every subsequent read or write to this parcel. If all
+ /// accesses are bounds checked, this call is still safe, but we can't rely
+ /// on that.
+ pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
+ self.borrowed_ref().set_data_position(pos)
+ }
+
+ /// Append a subset of another parcel.
+ ///
+ /// This appends `size` bytes of data from `other` starting at offset
+ /// `start` to the current parcel, or returns an error if not possible.
+ pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ self.borrowed().append_from(other, start, size)
+ }
+
+ /// Append the contents of another parcel.
+ pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+ self.borrowed().append_all_from(other)
}
}
// Data deserialization methods
-impl Parcel {
- /// Attempt to read a type that implements [`Deserialize`] from this
- /// `Parcel`.
+impl<'a> BorrowedParcel<'a> {
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel.
pub fn read<D: Deserialize>(&self) -> Result<D> {
D::deserialize(self)
}
- /// Read a vector size from the `Parcel` and resize the given output vector
- /// to be correctly sized for that amount of data.
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel
+ /// onto an existing value. This operation will overwrite the old value
+ /// partially or completely, depending on how much data is available.
+ pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
+ x.deserialize_from(self)
+ }
+
+ /// Safely read a sized parcelable.
+ ///
+ /// Read the size of a parcelable, compute the end position
+ /// of that parcelable, then build a sized readable sub-parcel
+ /// and call a closure with the sub-parcel as its parameter.
+ /// The closure can keep reading data from the sub-parcel
+ /// until it runs out of input data. The closure is responsible
+ /// for calling [`ReadableSubParcel::has_more_data`] to check for
+ /// more data before every read, at least until Rust generators
+ /// are stabilized.
+ /// After the closure returns, skip to the end of the current
+ /// parcelable regardless of how much the closure has read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// let mut parcelable = Default::default();
+ /// parcel.sized_read(|subparcel| {
+ /// if subparcel.has_more_data() {
+ /// parcelable.a = subparcel.read()?;
+ /// }
+ /// if subparcel.has_more_data() {
+ /// parcelable.b = subparcel.read()?;
+ /// }
+ /// Ok(())
+ /// });
+ /// ```
+ ///
+ pub fn sized_read<F>(&self, f: F) -> Result<()>
+ where
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ {
+ let start = self.get_data_position();
+ let parcelable_size: i32 = self.read()?;
+ if parcelable_size < 4 {
+ return Err(StatusCode::BAD_VALUE);
+ }
+
+ let end = start.checked_add(parcelable_size)
+ .ok_or(StatusCode::BAD_VALUE)?;
+ if end > self.get_data_size() {
+ return Err(StatusCode::NOT_ENOUGH_DATA);
+ }
+
+ let subparcel = ReadableSubParcel {
+ parcel: BorrowedParcel {
+ ptr: self.ptr,
+ _lifetime: PhantomData,
+ },
+ end_position: end,
+ };
+ f(subparcel)?;
+
+ // Advance the data position to the actual end,
+ // in case the closure read less data than was available
+ unsafe {
+ self.set_data_position(end)?;
+ }
+
+ Ok(())
+ }
+
+ /// Read a vector size from the parcel and resize the given output vector to
+ /// be correctly sized for that amount of data.
///
/// This method is used in AIDL-generated server side code for methods that
/// take a mutable slice reference parameter.
@@ -238,7 +543,7 @@
Ok(())
}
- /// Read a vector size from the `Parcel` and either create a correctly sized
+ /// Read a vector size from the parcel and either create a correctly sized
/// vector for that amount of data or set the output parameter to None if
/// the vector should be null.
///
@@ -264,11 +569,103 @@
}
}
-// Internal APIs
+/// A segment of a readable parcel, used for [`Parcel::sized_read`].
+pub struct ReadableSubParcel<'a> {
+ parcel: BorrowedParcel<'a>,
+ end_position: i32,
+}
+
+impl<'a> ReadableSubParcel<'a> {
+ /// Read a type that implements [`Deserialize`] from the sub-parcel.
+ pub fn read<D: Deserialize>(&self) -> Result<D> {
+ // The caller should have checked this,
+ // but it can't hurt to double-check
+ assert!(self.has_more_data());
+ D::deserialize(&self.parcel)
+ }
+
+ /// Check if the sub-parcel has more data to read
+ pub fn has_more_data(&self) -> bool {
+ self.parcel.get_data_position() < self.end_position
+ }
+}
+
impl Parcel {
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel.
+ pub fn read<D: Deserialize>(&self) -> Result<D> {
+ self.borrowed_ref().read()
+ }
+
+ /// Attempt to read a type that implements [`Deserialize`] from this parcel
+ /// onto an existing value. This operation will overwrite the old value
+ /// partially or completely, depending on how much data is available.
+ pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
+ self.borrowed_ref().read_onto(x)
+ }
+
+ /// Safely read a sized parcelable.
+ ///
+ /// Read the size of a parcelable, compute the end position
+ /// of that parcelable, then build a sized readable sub-parcel
+ /// and call a closure with the sub-parcel as its parameter.
+ /// The closure can keep reading data from the sub-parcel
+ /// until it runs out of input data. The closure is responsible
+ /// for calling [`ReadableSubParcel::has_more_data`] to check for
+ /// more data before every read, at least until Rust generators
+ /// are stabilized.
+ /// After the closure returns, skip to the end of the current
+ /// parcelable regardless of how much the closure has read.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// let mut parcelable = Default::default();
+ /// parcel.sized_read(|subparcel| {
+ /// if subparcel.has_more_data() {
+ /// parcelable.a = subparcel.read()?;
+ /// }
+ /// if subparcel.has_more_data() {
+ /// parcelable.b = subparcel.read()?;
+ /// }
+ /// Ok(())
+ /// });
+ /// ```
+ ///
+ pub fn sized_read<F>(&self, f: F) -> Result<()>
+ where
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ {
+ self.borrowed_ref().sized_read(f)
+ }
+
+ /// Read a vector size from the parcel and resize the given output vector to
+ /// be correctly sized for that amount of data.
+ ///
+ /// This method is used in AIDL-generated server side code for methods that
+ /// take a mutable slice reference parameter.
+ pub fn resize_out_vec<D: Default + Deserialize>(&self, out_vec: &mut Vec<D>) -> Result<()> {
+ self.borrowed_ref().resize_out_vec(out_vec)
+ }
+
+ /// Read a vector size from the parcel and either create a correctly sized
+ /// vector for that amount of data or set the output parameter to None if
+ /// the vector should be null.
+ ///
+ /// This method is used in AIDL-generated server side code for methods that
+ /// take a mutable slice reference parameter.
+ pub fn resize_nullable_out_vec<D: Default + Deserialize>(
+ &self,
+ out_vec: &mut Option<Vec<D>>,
+ ) -> Result<()> {
+ self.borrowed_ref().resize_nullable_out_vec(out_vec)
+ }
+}
+
+// Internal APIs
+impl<'a> BorrowedParcel<'a> {
pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
// `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
// null or a valid pointer to an `AIBinder`, both of which are
// valid, safe inputs to `AParcel_writeStrongBinder`.
@@ -288,7 +685,7 @@
pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
let mut binder = ptr::null_mut();
let status = unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
+ // Safety: `BorrowedParcel` always contains a valid pointer to an
// `AParcel`. We pass a valid, mutable out pointer to the `binder`
// parameter. After this call, `binder` will be either null or a
// valid pointer to an `AIBinder` owned by the caller.
@@ -308,54 +705,32 @@
impl Drop for Parcel {
fn drop(&mut self) {
// Run the C++ Parcel complete object destructor
- if let Self::Owned(ptr) = *self {
- unsafe {
- // Safety: `Parcel` always contains a valid pointer to an
- // `AParcel`. If we own the parcel, we can safely delete it
- // here.
- sys::AParcel_delete(ptr)
- }
+ unsafe {
+ // Safety: `Parcel` always contains a valid pointer to an
+ // `AParcel`. Since we own the parcel, we can safely delete it
+ // here.
+ sys::AParcel_delete(self.ptr.as_ptr())
}
}
}
-#[cfg(test)]
-impl Parcel {
- /// Create a new parcel tied to a bogus binder. TESTING ONLY!
- ///
- /// This can only be used for testing! All real parcel operations must be
- /// done in the callback to [`IBinder::transact`] or in
- /// [`Remotable::on_transact`] using the parcels provided to these methods.
- pub(crate) fn new_for_test(binder: &mut SpIBinder) -> Result<Self> {
- let mut input = ptr::null_mut();
- let status = unsafe {
- // Safety: `SpIBinder` guarantees that `binder` always contains a
- // valid pointer to an `AIBinder`. We pass a valid, mutable out
- // pointer to receive a newly constructed parcel. When successful
- // this function assigns a new pointer to an `AParcel` to `input`
- // and transfers ownership of this pointer to the caller. Thus,
- // after this call, `input` will either be null or point to a valid,
- // owned `AParcel`.
- sys::AIBinder_prepareTransaction(binder.as_native_mut(), &mut input)
- };
- status_result(status)?;
- unsafe {
- // Safety: `input` is either null or a valid, owned pointer to an
- // `AParcel`, so is valid to safe to
- // `Parcel::owned`. `Parcel::owned` takes ownership of the parcel
- // pointer.
- Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
- }
+impl fmt::Debug for Parcel {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Parcel")
+ .finish()
+ }
+}
+
+impl<'a> fmt::Debug for BorrowedParcel<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedParcel")
+ .finish()
}
}
#[test]
fn test_read_write() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert_eq!(parcel.read::<bool>(), Err(StatusCode::NOT_ENOUGH_DATA));
@@ -370,7 +745,7 @@
assert_eq!(parcel.read::<Option<String>>(), Ok(None));
assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL));
- assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE));
+ assert_eq!(parcel.borrowed_ref().read_binder().err(), Some(StatusCode::BAD_TYPE));
parcel.write(&1i32).unwrap();
@@ -385,11 +760,7 @@
#[test]
#[allow(clippy::float_cmp)]
fn test_read_data() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let str_start = parcel.get_data_position();
parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
@@ -400,7 +771,7 @@
assert_eq!(parcel.read::<i32>().unwrap(), 15);
let start = parcel.get_data_position();
- assert_eq!(parcel.read::<bool>().unwrap(), true);
+ assert!(parcel.read::<bool>().unwrap());
unsafe {
assert!(parcel.set_data_position(start).is_ok());
@@ -464,11 +835,7 @@
#[test]
fn test_utf8_utf16_conversions() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
assert!(parcel.write("Hello, Binder!").is_ok());
@@ -528,11 +895,7 @@
#[test]
fn test_sized_write() {
- use crate::binder::Interface;
- use crate::native::Binder;
-
- let mut service = Binder::new(()).as_binder();
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let mut parcel = Parcel::new();
let start = parcel.get_data_position();
let arr = [1i32, 2i32, 3i32];
@@ -560,3 +923,43 @@
&arr,
);
}
+
+#[test]
+fn test_append_from() {
+ let mut parcel1 = Parcel::new();
+ parcel1.write(&42i32).expect("Could not perform write");
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
+ assert_eq!(4, parcel2.get_data_size());
+ assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
+ assert_eq!(8, parcel2.get_data_size());
+ unsafe {
+ parcel2.set_data_position(0).unwrap();
+ }
+ assert_eq!(Ok(42), parcel2.read::<i32>());
+ assert_eq!(Ok(42), parcel2.read::<i32>());
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
+ assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2));
+ assert_eq!(4, parcel2.get_data_size());
+ unsafe {
+ parcel2.set_data_position(0).unwrap();
+ }
+ assert_eq!(Ok(42), parcel2.read::<i32>());
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
+ assert_eq!(2, parcel2.get_data_size());
+ unsafe {
+ parcel2.set_data_position(0).unwrap();
+ }
+ assert_eq!(Err(StatusCode::NOT_ENOUGH_DATA), parcel2.read::<i32>());
+
+ let mut parcel2 = Parcel::new();
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 4, 2));
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, 4));
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, -1, 4));
+ assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, -1));
+}
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 20e9178..4d3d59a 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
*/
use super::{
- Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+ Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
SerializeOption,
};
use crate::binder::AsNative;
@@ -23,7 +23,7 @@
use crate::sys;
use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
/// Rust version of the Java class android.os.ParcelFileDescriptor
#[derive(Debug)]
@@ -48,8 +48,30 @@
}
}
+impl AsRawFd for ParcelFileDescriptor {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for ParcelFileDescriptor {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw_fd()
+ }
+}
+
+impl PartialEq for ParcelFileDescriptor {
+ // Since ParcelFileDescriptors own the FD, if this function ever returns true (and it is used to
+ // compare two different objects), then it would imply that an FD is double-owned.
+ fn eq(&self, other: &Self) -> bool {
+ self.as_raw_fd() == other.as_raw_fd()
+ }
+}
+
+impl Eq for ParcelFileDescriptor {}
+
impl Serialize for ParcelFileDescriptor {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let fd = self.0.as_raw_fd();
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -66,7 +88,7 @@
impl SerializeArray for ParcelFileDescriptor {}
impl SerializeOption for ParcelFileDescriptor {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
if let Some(f) = this {
f.serialize(parcel)
} else {
@@ -82,10 +104,8 @@
}
}
-impl SerializeArray for Option<ParcelFileDescriptor> {}
-
impl DeserializeOption for ParcelFileDescriptor {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let mut fd = -1i32;
unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -114,10 +134,8 @@
}
}
-impl DeserializeArray for Option<ParcelFileDescriptor> {}
-
impl Deserialize for ParcelFileDescriptor {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Deserialize::deserialize(parcel)
.transpose()
.unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index f57788b..0c7e48d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,31 +14,62 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, FromIBinder, Strong};
+use crate::binder::{AsNative, FromIBinder, Stability, Strong};
use crate::error::{status_result, status_t, Result, Status, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::BorrowedParcel;
use crate::proxy::SpIBinder;
use crate::sys;
-use std::convert::TryInto;
+use std::convert::{TryFrom, TryInto};
use std::ffi::c_void;
use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit};
+use std::mem::{self, MaybeUninit, ManuallyDrop};
use std::ptr;
use std::slice;
+/// Super-trait for Binder parcelables.
+///
+/// This trait is equivalent `android::Parcelable` in C++,
+/// and defines a common interface that all parcelables need
+/// to implement.
+pub trait Parcelable {
+ /// Internal serialization function for parcelables.
+ ///
+ /// This method is mainly for internal use.
+ /// `Serialize::serialize` and its variants are generally
+ /// preferred over this function, since the former also
+ /// prepend a header.
+ fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
+
+ /// Internal deserialization function for parcelables.
+ ///
+ /// This method is mainly for internal use.
+ /// `Deserialize::deserialize` and its variants are generally
+ /// preferred over this function, since the former also
+ /// parse the additional header.
+ fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
+}
+
/// A struct whose instances can be written to a [`Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Serialize {
/// Serialize this instance into the given [`Parcel`].
- fn serialize(&self, parcel: &mut Parcel) -> Result<()>;
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
}
/// A struct whose instances can be restored from a [`Parcel`].
// Might be able to hook this up as a serde backend in the future?
pub trait Deserialize: Sized {
/// Deserialize an instance from the given [`Parcel`].
- fn deserialize(parcel: &Parcel) -> Result<Self>;
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
+
+ /// Deserialize an instance from the given [`Parcel`] onto the
+ /// current object. This operation will overwrite the old value
+ /// partially or completely, depending on how much data is available.
+ fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
+ *self = Self::deserialize(parcel)?;
+ Ok(())
+ }
}
/// Helper trait for types that can be serialized as arrays.
@@ -49,8 +80,8 @@
// We want the default implementation for most types, but an override for
// a few special ones like `readByteArray` for `u8`.
pub trait SerializeArray: Serialize + Sized {
- /// Serialize an array of this type into the given [`Parcel`].
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ /// Serialize an array of this type into the given parcel.
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let res = unsafe {
// Safety: Safe FFI, slice will always be a safe pointer to pass.
sys::AParcel_writeParcelableArray(
@@ -80,7 +111,7 @@
let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
- let mut parcel = match Parcel::borrowed(parcel) {
+ let mut parcel = match BorrowedParcel::from_raw(parcel) {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
@@ -95,8 +126,8 @@
/// Defaults to calling Deserialize::deserialize() manually for every element,
/// but can be overridden for custom implementations like `readByteArray`.
pub trait DeserializeArray: Deserialize {
- /// Deserialize an array of type from the given [`Parcel`].
- fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+ /// Deserialize an array of type from the given parcel.
+ fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
let res = unsafe {
// Safety: Safe FFI, vec is the correct opaque type expected by
@@ -142,7 +173,7 @@
None => return StatusCode::BAD_INDEX as status_t,
};
- let parcel = match Parcel::borrowed(parcel as *mut _) {
+ let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
@@ -154,6 +185,18 @@
StatusCode::OK as status_t
}
+/// Flag that specifies that the following parcelable is present.
+///
+/// This is the Rust equivalent of `Parcel::kNonNullParcelableFlag`
+/// from `include/binder/Parcel.h` in C++.
+pub const NON_NULL_PARCELABLE_FLAG: i32 = 1;
+
+/// Flag that specifies that the following parcelable is absent.
+///
+/// This is the Rust equivalent of `Parcel::kNullParcelableFlag`
+/// from `include/binder/Parcel.h` in C++.
+pub const NULL_PARCELABLE_FLAG: i32 = 0;
+
/// Helper trait for types that can be nullable when serialized.
// We really need this trait instead of implementing `Serialize for Option<T>`
// because of the Rust orphan rule which prevents us from doing
@@ -162,28 +205,36 @@
// We also use it to provide a default implementation for AIDL-generated
// parcelables.
pub trait SerializeOption: Serialize {
- /// Serialize an Option of this type into the given [`Parcel`].
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ /// Serialize an Option of this type into the given parcel.
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
if let Some(inner) = this {
- parcel.write(&1i32)?;
+ parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
parcel.write(inner)
} else {
- parcel.write(&0i32)
+ parcel.write(&NULL_PARCELABLE_FLAG)
}
}
}
/// Helper trait for types that can be nullable when deserialized.
pub trait DeserializeOption: Deserialize {
- /// Deserialize an Option of this type from the given [`Parcel`].
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ /// Deserialize an Option of this type from the given parcel.
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let null: i32 = parcel.read()?;
- if null == 0 {
+ if null == NULL_PARCELABLE_FLAG {
Ok(None)
} else {
parcel.read().map(Some)
}
}
+
+ /// Deserialize an Option of this type from the given parcel onto the
+ /// current object. This operation will overwrite the current value
+ /// partially or completely, depending on how much data is available.
+ fn deserialize_option_from(this: &mut Option<Self>, parcel: &BorrowedParcel<'_>) -> Result<()> {
+ *this = Self::deserialize_option(parcel)?;
+ Ok(())
+ }
}
/// Callback to allocate a vector for parcel array read functions.
@@ -246,10 +297,23 @@
};
}
+/// Safety: All elements in the vector must be properly initialized.
+unsafe fn vec_assume_init<T>(vec: Vec<MaybeUninit<T>>) -> Vec<T> {
+ // We can convert from Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T>
+ // has the same alignment and size as T, so the pointer to the vector
+ // allocation will be compatible.
+ let mut vec = ManuallyDrop::new(vec);
+ Vec::from_raw_parts(
+ vec.as_mut_ptr().cast(),
+ vec.len(),
+ vec.capacity(),
+ )
+}
+
macro_rules! impl_parcelable {
{Serialize, $ty:ty, $write_fn:path} => {
impl Serialize for $ty {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`, and any `$ty` literal value is safe to pass to
@@ -262,7 +326,7 @@
{Deserialize, $ty:ty, $read_fn:path} => {
impl Deserialize for $ty {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut val = Self::default();
unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -278,7 +342,7 @@
{SerializeArray, $ty:ty, $write_array_fn:path} => {
impl SerializeArray for $ty {
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
@@ -302,7 +366,7 @@
{DeserializeArray, $ty:ty, $read_array_fn:path} => {
impl DeserializeArray for $ty {
- fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+ fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -320,11 +384,8 @@
// Safety: We are assuming that the NDK correctly
// initialized every element of the vector by now, so we
// know that all the MaybeUninits are now properly
- // initialized. We can transmute from Vec<MaybeUninit<T>> to
- // Vec<T> because MaybeUninit<T> has the same alignment and
- // size as T, so the pointer to the vector allocation will
- // be compatible.
- mem::transmute(vec)
+ // initialized.
+ vec.map(|vec| vec_assume_init(vec))
};
Ok(vec)
}
@@ -332,6 +393,9 @@
};
}
+impl<T: DeserializeOption> DeserializeArray for Option<T> {}
+impl<T: SerializeOption> SerializeArray for Option<T> {}
+
parcelable_primitives! {
impl Serialize for bool = sys::AParcel_writeBool;
impl Deserialize for bool = sys::AParcel_readBool;
@@ -389,19 +453,19 @@
impl DeserializeArray for bool {}
impl Serialize for u8 {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
(*self as i8).serialize(parcel)
}
}
impl Deserialize for u8 {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
i8::deserialize(parcel).map(|v| v as u8)
}
}
impl SerializeArray for u8 {
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
@@ -420,19 +484,19 @@
}
impl Serialize for i16 {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
(*self as u16).serialize(parcel)
}
}
impl Deserialize for i16 {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
u16::deserialize(parcel).map(|v| v as i16)
}
}
impl SerializeArray for i16 {
- fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+ fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
// `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
@@ -451,7 +515,7 @@
}
impl SerializeOption for str {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
match this {
None => unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -486,10 +550,8 @@
}
}
-impl SerializeArray for Option<&str> {}
-
impl Serialize for str {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Some(self).serialize(parcel)
}
}
@@ -497,7 +559,7 @@
impl SerializeArray for &str {}
impl Serialize for String {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Some(self.as_str()).serialize(parcel)
}
}
@@ -505,15 +567,13 @@
impl SerializeArray for String {}
impl SerializeOption for String {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(String::as_str), parcel)
}
}
-impl SerializeArray for Option<String> {}
-
impl Deserialize for Option<String> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut vec: Option<Vec<u8>> = None;
let status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an `AParcel`.
@@ -541,7 +601,7 @@
impl DeserializeArray for Option<String> {}
impl Deserialize for String {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Deserialize::deserialize(parcel)
.transpose()
.unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -551,19 +611,19 @@
impl DeserializeArray for String {}
impl<T: SerializeArray> Serialize for [T] {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeArray::serialize_array(self, parcel)
}
}
impl<T: SerializeArray> Serialize for Vec<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeArray::serialize_array(&self[..], parcel)
}
}
impl<T: SerializeArray> SerializeOption for [T] {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
if let Some(v) = this {
SerializeArray::serialize_array(v, parcel)
} else {
@@ -573,13 +633,13 @@
}
impl<T: SerializeArray> SerializeOption for Vec<T> {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(Vec::as_slice), parcel)
}
}
impl<T: DeserializeArray> Deserialize for Vec<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
DeserializeArray::deserialize_array(parcel)
.transpose()
.unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -587,13 +647,58 @@
}
impl<T: DeserializeArray> DeserializeOption for Vec<T> {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
DeserializeArray::deserialize_array(parcel)
}
}
+impl<T: SerializeArray, const N: usize> Serialize for [T; N] {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ // forwards to T::serialize_array.
+ SerializeArray::serialize_array(self, parcel)
+ }
+}
+
+impl<T: SerializeArray, const N: usize> SerializeOption for [T; N] {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ SerializeOption::serialize_option(this.map(|arr| &arr[..]), parcel)
+ }
+}
+
+impl<T: SerializeArray, const N: usize> SerializeArray for [T; N] {}
+
+impl<T: DeserializeArray, const N: usize> Deserialize for [T; N] {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+ let vec = DeserializeArray::deserialize_array(parcel)
+ .transpose()
+ .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))?;
+ vec.try_into().or(Err(StatusCode::BAD_VALUE))
+ }
+}
+
+impl<T: DeserializeArray, const N: usize> DeserializeOption for [T; N] {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
+ let vec = DeserializeArray::deserialize_array(parcel)?;
+ vec.map(|v| v.try_into().or(Err(StatusCode::BAD_VALUE))).transpose()
+ }
+}
+
+impl<T: DeserializeArray, const N: usize> DeserializeArray for [T; N] {}
+
+impl Serialize for Stability {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ i32::from(*self).serialize(parcel)
+ }
+}
+
+impl Deserialize for Stability {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+ i32::deserialize(parcel).and_then(Stability::try_from)
+ }
+}
+
impl Serialize for Status {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
unsafe {
// Safety: `Parcel` always contains a valid pointer to an `AParcel`
// and `Status` always contains a valid pointer to an `AStatus`, so
@@ -608,7 +713,7 @@
}
impl Deserialize for Status {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let mut status_ptr = ptr::null_mut();
let ret_status = unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -629,361 +734,488 @@
}
impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Serialize::serialize(&**self, parcel)
}
}
impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.map(|b| &**b), parcel)
}
}
+impl<T: Serialize + FromIBinder + ?Sized> SerializeArray for Strong<T> {}
+
impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
let ibinder: SpIBinder = parcel.read()?;
FromIBinder::try_from(ibinder)
}
}
impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
let ibinder: Option<SpIBinder> = parcel.read()?;
ibinder.map(FromIBinder::try_from).transpose()
}
}
+impl<T: FromIBinder + ?Sized> DeserializeArray for Strong<T> {}
+
// We need these to support Option<&T> for all T
impl<T: Serialize + ?Sized> Serialize for &T {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
Serialize::serialize(*self, parcel)
}
}
impl<T: SerializeOption + ?Sized> SerializeOption for &T {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(this.copied(), parcel)
}
}
impl<T: SerializeOption> Serialize for Option<T> {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
SerializeOption::serialize_option(self.as_ref(), parcel)
}
}
impl<T: DeserializeOption> Deserialize for Option<T> {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
DeserializeOption::deserialize_option(parcel)
}
+
+ fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
+ DeserializeOption::deserialize_option_from(self, parcel)
+ }
}
-#[test]
-fn test_custom_parcelable() {
- use crate::binder::Interface;
- use crate::native::Binder;
- let mut service = Binder::new(()).as_binder();
-
- struct Custom(u32, bool, String, Vec<String>);
-
- impl Serialize for Custom {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
- self.0.serialize(parcel)?;
- self.1.serialize(parcel)?;
- self.2.serialize(parcel)?;
- self.3.serialize(parcel)
+/// Implement `Serialize` trait and friends for a parcelable
+///
+/// This is an internal macro used by the AIDL compiler to implement
+/// `Serialize`, `SerializeArray` and `SerializeOption` for
+/// structured parcelables. The target type must implement the
+/// `Parcelable` trait.
+/// ```
+#[macro_export]
+macro_rules! impl_serialize_for_parcelable {
+ ($parcelable:ident) => {
+ impl $crate::binder_impl::Serialize for $parcelable {
+ fn serialize(
+ &self,
+ parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
+ <Self as $crate::binder_impl::SerializeOption>::serialize_option(Some(self), parcel)
+ }
}
- }
- impl Deserialize for Custom {
- fn deserialize(parcel: &Parcel) -> Result<Self> {
- Ok(Custom(
- parcel.read()?,
- parcel.read()?,
- parcel.read()?,
- parcel.read::<Option<Vec<String>>>()?.unwrap(),
- ))
+ impl $crate::binder_impl::SerializeArray for $parcelable {}
+
+ impl $crate::binder_impl::SerializeOption for $parcelable {
+ fn serialize_option(
+ this: Option<&Self>,
+ parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
+ if let Some(this) = this {
+ use $crate::Parcelable;
+ parcel.write(&$crate::binder_impl::NON_NULL_PARCELABLE_FLAG)?;
+ this.write_to_parcel(parcel)
+ } else {
+ parcel.write(&$crate::binder_impl::NULL_PARCELABLE_FLAG)
+ }
+ }
}
- }
-
- let string8 = "Custom Parcelable".to_string();
-
- let s1 = "str1".to_string();
- let s2 = "str2".to_string();
- let s3 = "str3".to_string();
-
- let strs = vec![s1, s2, s3];
-
- let custom = Custom(123_456_789, true, string8, strs);
-
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
- let start = parcel.get_data_position();
-
- assert!(custom.serialize(&mut parcel).is_ok());
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let custom2 = Custom::deserialize(&parcel).unwrap();
-
- assert_eq!(custom2.0, 123_456_789);
- assert!(custom2.1);
- assert_eq!(custom2.2, custom.2);
- assert_eq!(custom2.3, custom.3);
+ };
}
-#[test]
-#[allow(clippy::excessive_precision)]
-fn test_slice_parcelables() {
- use crate::binder::Interface;
- use crate::native::Binder;
- let mut service = Binder::new(()).as_binder();
+/// Implement `Deserialize` trait and friends for a parcelable
+///
+/// This is an internal macro used by the AIDL compiler to implement
+/// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
+/// structured parcelables. The target type must implement the
+/// `Parcelable` trait.
+#[macro_export]
+macro_rules! impl_deserialize_for_parcelable {
+ ($parcelable:ident) => {
+ impl $crate::binder_impl::Deserialize for $parcelable {
+ fn deserialize(
+ parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<Self, $crate::StatusCode> {
+ $crate::binder_impl::DeserializeOption::deserialize_option(parcel)
+ .transpose()
+ .unwrap_or(Err($crate::StatusCode::UNEXPECTED_NULL))
+ }
+ fn deserialize_from(
+ &mut self,
+ parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
+ let status: i32 = parcel.read()?;
+ if status == $crate::binder_impl::NULL_PARCELABLE_FLAG {
+ Err($crate::StatusCode::UNEXPECTED_NULL)
+ } else {
+ use $crate::Parcelable;
+ self.read_from_parcel(parcel)
+ }
+ }
+ }
- let bools = [true, false, false, true];
+ impl $crate::binder_impl::DeserializeArray for $parcelable {}
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
- let start = parcel.get_data_position();
+ impl $crate::binder_impl::DeserializeOption for $parcelable {
+ fn deserialize_option(
+ parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<Option<Self>, $crate::StatusCode> {
+ let mut result = None;
+ Self::deserialize_option_from(&mut result, parcel)?;
+ Ok(result)
+ }
+ fn deserialize_option_from(
+ this: &mut Option<Self>,
+ parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
+ let status: i32 = parcel.read()?;
+ if status == $crate::binder_impl::NULL_PARCELABLE_FLAG {
+ *this = None;
+ Ok(())
+ } else {
+ use $crate::Parcelable;
+ this.get_or_insert_with(Self::default)
+ .read_from_parcel(parcel)
+ }
+ }
+ }
+ };
+}
- assert!(bools.serialize(&mut parcel).is_ok());
+impl<T: Serialize> Serialize for Box<T> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ Serialize::serialize(&**self, parcel)
+ }
+}
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
+impl<T: Deserialize> Deserialize for Box<T> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+ Deserialize::deserialize(parcel).map(Box::new)
+ }
+}
+
+impl<T: SerializeOption> SerializeOption for Box<T> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ SerializeOption::serialize_option(this.map(|inner| &**inner), parcel)
+ }
+}
+
+impl<T: DeserializeOption> DeserializeOption for Box<T> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
+ DeserializeOption::deserialize_option(parcel).map(|t| t.map(Box::new))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::parcel::Parcel;
+ use super::*;
+
+ #[test]
+ fn test_custom_parcelable() {
+ struct Custom(u32, bool, String, Vec<String>);
+
+ impl Serialize for Custom {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+ self.0.serialize(parcel)?;
+ self.1.serialize(parcel)?;
+ self.2.serialize(parcel)?;
+ self.3.serialize(parcel)
+ }
+ }
+
+ impl Deserialize for Custom {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+ Ok(Custom(
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read::<Option<Vec<String>>>()?.unwrap(),
+ ))
+ }
+ }
+
+ let string8 = "Custom Parcelable".to_string();
+
+ let s1 = "str1".to_string();
+ let s2 = "str2".to_string();
+ let s3 = "str3".to_string();
+
+ let strs = vec![s1, s2, s3];
+
+ let custom = Custom(123_456_789, true, string8, strs);
+
+ let mut parcel = Parcel::new();
+ let start = parcel.get_data_position();
+
+ assert!(custom.serialize(&mut parcel.borrowed()).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let custom2 = Custom::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(custom2.0, 123_456_789);
+ assert!(custom2.1);
+ assert_eq!(custom2.2, custom.2);
+ assert_eq!(custom2.3, custom.3);
}
- assert_eq!(parcel.read::<u32>().unwrap(), 4);
- assert_eq!(parcel.read::<u32>().unwrap(), 1);
- assert_eq!(parcel.read::<u32>().unwrap(), 0);
- assert_eq!(parcel.read::<u32>().unwrap(), 0);
- assert_eq!(parcel.read::<u32>().unwrap(), 1);
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
+ #[test]
+ #[allow(clippy::excessive_precision)]
+ fn test_slice_parcelables() {
+ let bools = [true, false, false, true];
+
+ let mut parcel = Parcel::new();
+ let start = parcel.get_data_position();
+
+ assert!(bools.serialize(&mut parcel.borrowed()).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4);
+ assert_eq!(parcel.read::<u32>().unwrap(), 1);
+ assert_eq!(parcel.read::<u32>().unwrap(), 0);
+ assert_eq!(parcel.read::<u32>().unwrap(), 0);
+ assert_eq!(parcel.read::<u32>().unwrap(), 1);
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<bool>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [true, false, false, true]);
+
+ let u8s = [101u8, 255, 42, 117];
+
+ let mut parcel = Parcel::new();
+ let start = parcel.get_data_position();
+
+ assert!(parcel.write(&u8s[..]).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+ assert_eq!(vec, [101, 255, 42, 117]);
+
+ let i8s = [-128i8, 127, 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert!(parcel.write(&i8s[..]).is_ok());
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+ assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
+
+ let u16s = [u16::max_value(), 12_345, 42, 117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(u16s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+
+ let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(i16s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<i16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+
+ let u32s = [u32::max_value(), 12_345, 42, 117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(u32s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+
+ let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(i32s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<i32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+
+ let u64s = [u64::max_value(), 12_345, 42, 117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(u64s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<u64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+
+ let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(i64s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<i64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+
+ let f32s = [
+ std::f32::NAN,
+ std::f32::INFINITY,
+ 1.23456789,
+ std::f32::EPSILON,
+ ];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(f32s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<f32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ // NAN != NAN so we can't use it in the assert_eq:
+ assert!(vec[0].is_nan());
+ assert_eq!(vec[1..], f32s[1..]);
+
+ let f64s = [
+ std::f64::NAN,
+ std::f64::INFINITY,
+ 1.234567890123456789,
+ std::f64::EPSILON,
+ ];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(f64s.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<f64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ // NAN != NAN so we can't use it in the assert_eq:
+ assert!(vec[0].is_nan());
+ assert_eq!(vec[1..], f64s[1..]);
+
+ let s1 = "Hello, Binder!";
+ let s2 = "This is a utf8 string.";
+ let s3 = "Some more text here.";
+ let s4 = "Embedded nulls \0 \0";
+
+ let strs = [s1, s2, s3, s4];
+
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+ assert!(strs.serialize(&mut parcel.borrowed()).is_ok());
+ unsafe {
+ assert!(parcel.set_data_position(start).is_ok());
+ }
+
+ let vec = Vec::<String>::deserialize(parcel.borrowed_ref()).unwrap();
+
+ assert_eq!(vec, strs);
}
-
- let vec = Vec::<bool>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [true, false, false, true]);
-
- let u8s = [101u8, 255, 42, 117];
-
- let mut parcel = Parcel::new_for_test(&mut service).unwrap();
- let start = parcel.get_data_position();
-
- assert!(parcel.write(&u8s[..]).is_ok());
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u8>::deserialize(&parcel).unwrap();
- assert_eq!(vec, [101, 255, 42, 117]);
-
- let i8s = [-128i8, 127, 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert!(parcel.write(&i8s[..]).is_ok());
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u8>::deserialize(&parcel).unwrap();
- assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
-
- let u16s = [u16::max_value(), 12_345, 42, 117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(u16s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u16>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
-
- let i16s = [i16::max_value(), i16::min_value(), 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(i16s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<i16>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
-
- let u32s = [u32::max_value(), 12_345, 42, 117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(u32s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u32>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
-
- let i32s = [i32::max_value(), i32::min_value(), 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(i32s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<i32>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
-
- let u64s = [u64::max_value(), 12_345, 42, 117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(u64s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<u64>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
-
- let i64s = [i64::max_value(), i64::min_value(), 42, -117];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(i64s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<i64>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
-
- let f32s = [
- std::f32::NAN,
- std::f32::INFINITY,
- 1.23456789,
- std::f32::EPSILON,
- ];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(f32s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<f32>::deserialize(&parcel).unwrap();
-
- // NAN != NAN so we can't use it in the assert_eq:
- assert!(vec[0].is_nan());
- assert_eq!(vec[1..], f32s[1..]);
-
- let f64s = [
- std::f64::NAN,
- std::f64::INFINITY,
- 1.234567890123456789,
- std::f64::EPSILON,
- ];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(f64s.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<f64>::deserialize(&parcel).unwrap();
-
- // NAN != NAN so we can't use it in the assert_eq:
- assert!(vec[0].is_nan());
- assert_eq!(vec[1..], f64s[1..]);
-
- let s1 = "Hello, Binder!";
- let s2 = "This is a utf8 string.";
- let s3 = "Some more text here.";
- let s4 = "Embedded nulls \0 \0";
-
- let strs = [s1, s2, s3, s4];
-
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
- assert!(strs.serialize(&mut parcel).is_ok());
- unsafe {
- assert!(parcel.set_data_position(start).is_ok());
- }
-
- let vec = Vec::<String>::deserialize(&parcel).unwrap();
-
- assert_eq!(vec, strs);
}
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
new file mode 100644
index 0000000..432da5d
--- /dev/null
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+use crate::binder::Stability;
+use crate::error::StatusCode;
+use crate::parcel::{
+ BorrowedParcel, Deserialize, Parcel, Parcelable, Serialize, NON_NULL_PARCELABLE_FLAG,
+ NULL_PARCELABLE_FLAG,
+};
+
+use downcast_rs::{impl_downcast, DowncastSync};
+use std::any::Any;
+use std::sync::{Arc, Mutex};
+
+/// Metadata that `ParcelableHolder` needs for all parcelables.
+///
+/// The compiler auto-generates implementations of this trait
+/// for AIDL parcelables.
+pub trait ParcelableMetadata {
+ /// The Binder parcelable descriptor string.
+ ///
+ /// This string is a unique identifier for a Binder parcelable.
+ fn get_descriptor() -> &'static str;
+
+ /// The Binder parcelable stability.
+ fn get_stability(&self) -> Stability {
+ Stability::Local
+ }
+}
+
+trait AnyParcelable: DowncastSync + Parcelable + std::fmt::Debug {}
+impl_downcast!(sync AnyParcelable);
+impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + std::fmt::Debug {}
+
+#[derive(Debug, Clone)]
+enum ParcelableHolderData {
+ Empty,
+ Parcelable {
+ parcelable: Arc<dyn AnyParcelable>,
+ name: String,
+ },
+ Parcel(Parcel),
+}
+
+/// A container that can hold any arbitrary `Parcelable`.
+///
+/// This type is currently used for AIDL parcelable fields.
+///
+/// `ParcelableHolder` is currently not thread-safe (neither
+/// `Send` nor `Sync`), mainly because it internally contains
+/// a `Parcel` which in turn is not thread-safe.
+#[derive(Debug)]
+pub struct ParcelableHolder {
+ // This is a `Mutex` because of `get_parcelable`
+ // which takes `&self` for consistency with C++.
+ // We could make `get_parcelable` take a `&mut self`
+ // and get rid of the `Mutex` here for a performance
+ // improvement, but then callers would require a mutable
+ // `ParcelableHolder` even for that getter method.
+ data: Mutex<ParcelableHolderData>,
+ stability: Stability,
+}
+
+impl ParcelableHolder {
+ /// Construct a new `ParcelableHolder` with the given stability.
+ pub fn new(stability: Stability) -> Self {
+ Self {
+ data: Mutex::new(ParcelableHolderData::Empty),
+ stability,
+ }
+ }
+
+ /// Reset the contents of this `ParcelableHolder`.
+ ///
+ /// Note that this method does not reset the stability,
+ /// only the contents.
+ pub fn reset(&mut self) {
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
+ // We could also clear stability here, but C++ doesn't
+ }
+
+ /// Set the parcelable contained in this `ParcelableHolder`.
+ pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<(), StatusCode>
+ where
+ T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
+ {
+ if self.stability > p.get_stability() {
+ return Err(StatusCode::BAD_VALUE);
+ }
+
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
+ parcelable: p,
+ name: T::get_descriptor().into(),
+ };
+
+ Ok(())
+ }
+
+ /// Retrieve the parcelable stored in this `ParcelableHolder`.
+ ///
+ /// This method attempts to retrieve the parcelable inside
+ /// the current object as a parcelable of type `T`.
+ /// The object is validated against `T` by checking that
+ /// its parcelable descriptor matches the one returned
+ /// by `T::get_descriptor()`.
+ ///
+ /// Returns one of the following:
+ /// * `Err(_)` in case of error
+ /// * `Ok(None)` if the holder is empty or the descriptor does not match
+ /// * `Ok(Some(_))` if the object holds a parcelable of type `T`
+ /// with the correct descriptor
+ pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>, StatusCode>
+ where
+ T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
+ {
+ let parcelable_desc = T::get_descriptor();
+ let mut data = self.data.lock().unwrap();
+ match *data {
+ ParcelableHolderData::Empty => Ok(None),
+ ParcelableHolderData::Parcelable {
+ ref parcelable,
+ ref name,
+ } => {
+ if name != parcelable_desc {
+ return Err(StatusCode::BAD_VALUE);
+ }
+
+ match Arc::clone(parcelable).downcast_arc::<T>() {
+ Err(_) => Err(StatusCode::BAD_VALUE),
+ Ok(x) => Ok(Some(x)),
+ }
+ }
+ ParcelableHolderData::Parcel(ref mut parcel) => {
+ unsafe {
+ // Safety: 0 should always be a valid position.
+ parcel.set_data_position(0)?;
+ }
+
+ let name: String = parcel.read()?;
+ if name != parcelable_desc {
+ return Ok(None);
+ }
+
+ let mut parcelable = T::default();
+ parcelable.read_from_parcel(parcel.borrowed_ref())?;
+
+ let parcelable = Arc::new(parcelable);
+ let result = Arc::clone(&parcelable);
+ *data = ParcelableHolderData::Parcelable { parcelable, name };
+
+ Ok(Some(result))
+ }
+ }
+ }
+
+ /// Return the stability value of this object.
+ pub fn get_stability(&self) -> Stability {
+ self.stability
+ }
+}
+
+impl Serialize for ParcelableHolder {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
+ parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
+ self.write_to_parcel(parcel)
+ }
+}
+
+impl Deserialize for ParcelableHolder {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self, StatusCode> {
+ let status: i32 = parcel.read()?;
+ if status == NULL_PARCELABLE_FLAG {
+ Err(StatusCode::UNEXPECTED_NULL)
+ } else {
+ let mut parcelable = ParcelableHolder::new(Default::default());
+ parcelable.read_from_parcel(parcel)?;
+ Ok(parcelable)
+ }
+ }
+}
+
+impl Parcelable for ParcelableHolder {
+ fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
+ parcel.write(&self.stability)?;
+
+ let mut data = self.data.lock().unwrap();
+ match *data {
+ ParcelableHolderData::Empty => parcel.write(&0i32),
+ ParcelableHolderData::Parcelable {
+ ref parcelable,
+ ref name,
+ } => {
+ let length_start = parcel.get_data_position();
+ parcel.write(&0i32)?;
+
+ let data_start = parcel.get_data_position();
+ parcel.write(name)?;
+ parcelable.write_to_parcel(parcel)?;
+
+ let end = parcel.get_data_position();
+ unsafe {
+ // Safety: we got the position from `get_data_position`.
+ parcel.set_data_position(length_start)?;
+ }
+
+ assert!(end >= data_start);
+ parcel.write(&(end - data_start))?;
+ unsafe {
+ // Safety: we got the position from `get_data_position`.
+ parcel.set_data_position(end)?;
+ }
+
+ Ok(())
+ }
+ ParcelableHolderData::Parcel(ref mut p) => {
+ parcel.write(&p.get_data_size())?;
+ parcel.append_all_from(&*p)
+ }
+ }
+ }
+
+ fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
+ if self.stability != parcel.read()? {
+ return Err(StatusCode::BAD_VALUE);
+ }
+
+ let data_size: i32 = parcel.read()?;
+ if data_size < 0 {
+ // C++ returns BAD_VALUE here,
+ // while Java returns ILLEGAL_ARGUMENT
+ return Err(StatusCode::BAD_VALUE);
+ }
+ if data_size == 0 {
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
+ return Ok(());
+ }
+
+ // TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
+ // only go up to i32::MAX because that's what our API uses everywhere
+ let data_start = parcel.get_data_position();
+ let data_end = data_start
+ .checked_add(data_size)
+ .ok_or(StatusCode::BAD_VALUE)?;
+
+ let mut new_parcel = Parcel::new();
+ new_parcel.append_from(parcel, data_start, data_size)?;
+ *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
+
+ unsafe {
+ // Safety: `append_from` checks if `data_size` overflows
+ // `parcel` and returns `BAD_VALUE` if that happens. We also
+ // explicitly check for negative and zero `data_size` above,
+ // so `data_end` is guaranteed to be greater than `data_start`.
+ parcel.set_data_position(data_end)?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 52036f5..e3e4730 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,23 +22,25 @@
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
- Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
- SerializeOption,
+ Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
};
use crate::sys;
use std::cmp::Ordering;
use std::convert::TryInto;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
use std::fmt;
+use std::mem;
+use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
+use std::sync::Arc;
/// A strong reference to a Binder remote object.
///
/// This struct encapsulates the generic C++ `sp<IBinder>` class. This wrapper
/// is untyped; typed interface access is implemented by the AIDL compiler.
-pub struct SpIBinder(*mut sys::AIBinder);
+pub struct SpIBinder(ptr::NonNull<sys::AIBinder>);
impl fmt::Debug for SpIBinder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -48,9 +50,14 @@
/// # Safety
///
-/// An `SpIBinder` is a handle to a C++ IBinder, which is thread-safe
+/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
unsafe impl Send for SpIBinder {}
+/// # Safety
+///
+/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+unsafe impl Sync for SpIBinder {}
+
impl SpIBinder {
/// Create an `SpIBinder` wrapper object from a raw `AIBinder` pointer.
///
@@ -69,7 +76,7 @@
/// to an `AIBinder`, which will remain valid for the entire lifetime of the
/// `SpIBinder` (we keep a strong reference, and only decrement on drop).
pub(crate) unsafe fn from_raw(ptr: *mut sys::AIBinder) -> Option<Self> {
- ptr.as_mut().map(|p| Self(p))
+ ptr::NonNull::new(ptr).map(Self)
}
/// Extract a raw `AIBinder` pointer from this wrapper.
@@ -83,7 +90,7 @@
/// The SpIBinder object retains ownership of the AIBinder and the caller
/// should not attempt to free the returned pointer.
pub unsafe fn as_raw(&self) -> *mut sys::AIBinder {
- self.0
+ self.0.as_ptr()
}
/// Return true if this binder object is hosted in a different process than
@@ -125,6 +132,21 @@
}
}
+pub mod unstable_api {
+ use super::{sys, SpIBinder};
+
+ /// A temporary API to allow the client to create a `SpIBinder` from a `sys::AIBinder`. This is
+ /// needed to bridge RPC binder, which doesn't have Rust API yet.
+ /// TODO(b/184872979): remove once the Rust API is created.
+ ///
+ /// # Safety
+ ///
+ /// See `SpIBinder::from_raw`.
+ pub unsafe fn new_spibinder(ptr: *mut sys::AIBinder) -> Option<SpIBinder> {
+ SpIBinder::from_raw(ptr)
+ }
+}
+
/// An object that can be associate with an [`InterfaceClass`].
pub trait AssociateClass {
/// Check if this object is a valid object for the given interface class
@@ -156,13 +178,13 @@
// Safety: SpIBinder always holds a valid `AIBinder` pointer, so
// this pointer is always safe to pass to `AIBinder_lt` (null is
// also safe to pass to this function, but we should never do that).
- sys::AIBinder_lt(self.0, other.0)
+ sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr())
};
let greater_than = unsafe {
// Safety: SpIBinder always holds a valid `AIBinder` pointer, so
// this pointer is always safe to pass to `AIBinder_lt` (null is
// also safe to pass to this function, but we should never do that).
- sys::AIBinder_lt(other.0, self.0)
+ sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr())
};
if !less_than && !greater_than {
Ordering::Equal
@@ -182,7 +204,7 @@
impl PartialEq for SpIBinder {
fn eq(&self, other: &Self) -> bool {
- ptr::eq(self.0, other.0)
+ ptr::eq(self.0.as_ptr(), other.0.as_ptr())
}
}
@@ -194,7 +216,7 @@
// Safety: Cloning a strong reference must increment the reference
// count. We are guaranteed by the `SpIBinder` constructor
// invariants that `self.0` is always a valid `AIBinder` pointer.
- sys::AIBinder_incStrong(self.0);
+ sys::AIBinder_incStrong(self.0.as_ptr());
}
Self(self.0)
}
@@ -213,13 +235,7 @@
}
impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
- /// Perform a binder transaction
- fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
- &self,
- code: TransactionCode,
- flags: TransactionFlags,
- input_callback: F,
- ) -> Result<Parcel> {
+ fn prepare_transact(&self) -> Result<Parcel> {
let mut input = ptr::null_mut();
let status = unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -232,14 +248,23 @@
// pointer, or null.
sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
};
+
status_result(status)?;
- let mut input = unsafe {
+
+ unsafe {
// Safety: At this point, `input` is either a valid, owned `AParcel`
- // pointer, or null. `Parcel::owned` safely handles both cases,
+ // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
// taking ownership of the parcel.
- Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)?
- };
- input_callback(&mut input)?;
+ Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
+ }
+ }
+
+ fn submit_transact(
+ &self,
+ code: TransactionCode,
+ data: Parcel,
+ flags: TransactionFlags,
+ ) -> Result<Parcel> {
let mut reply = ptr::null_mut();
let status = unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -255,13 +280,13 @@
// only providing `on_transact` with an immutable reference to
// `self`.
//
- // This call takes ownership of the `input` parcel pointer, and
+ // This call takes ownership of the `data` parcel pointer, and
// passes ownership of the `reply` out parameter to its caller. It
// does not affect ownership of the `binder` parameter.
sys::AIBinder_transact(
self.as_native() as *mut sys::AIBinder,
code,
- &mut input.into_raw(),
+ &mut data.into_raw(),
&mut reply,
flags,
)
@@ -273,9 +298,8 @@
// after the call to `AIBinder_transact` above, so we can
// construct a `Parcel` out of it. `AIBinder_transact` passes
// ownership of the `reply` parcel to Rust, so we need to
- // construct an owned variant. `Parcel::owned` takes ownership
- // of the parcel pointer.
- Parcel::owned(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+ // construct an owned variant.
+ Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
}
}
@@ -289,17 +313,7 @@
}
}
- fn ping_binder(&mut self) -> Result<()> {
- let status = unsafe {
- // Safety: `SpIBinder` guarantees that `self` always contains a
- // valid pointer to an `AIBinder`.
- //
- // This call does not affect ownership of its pointer parameter.
- sys::AIBinder_ping(self.as_native_mut())
- };
- status_result(status)
- }
-
+ #[cfg(not(android_vndk))]
fn set_requesting_sid(&mut self, enable: bool) {
unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
}
@@ -358,13 +372,17 @@
// Safety: `SpIBinder` guarantees that `self` always contains a
// valid pointer to an `AIBinder`. `recipient` can always be
// converted into a valid pointer to an
- // `AIBinder_DeathRecipient`. Any value is safe to pass as the
- // cookie, although we depend on this value being set by
- // `get_cookie` when the death recipient callback is called.
+ // `AIBinder_DeathRecipient`.
+ //
+ // The cookie is also the correct pointer, and by calling new_cookie,
+ // we have created a new ref-count to the cookie, which linkToDeath
+ // takes ownership of. Once the DeathRecipient is unlinked for any
+ // reason (including if this call fails), the onUnlinked callback
+ // will consume that ref-count.
sys::AIBinder_linkToDeath(
self.as_native_mut(),
recipient.as_native_mut(),
- recipient.get_cookie(),
+ recipient.new_cookie(),
)
})
}
@@ -384,25 +402,35 @@
)
})
}
+
+ fn ping_binder(&mut self) -> Result<()> {
+ let status = unsafe {
+ // Safety: `SpIBinder` guarantees that `self` always contains a
+ // valid pointer to an `AIBinder`.
+ //
+ // This call does not affect ownership of its pointer parameter.
+ sys::AIBinder_ping(self.as_native_mut())
+ };
+ status_result(status)
+ }
}
impl Serialize for SpIBinder {
- fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+ fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(Some(self))
}
}
impl SerializeOption for SpIBinder {
- fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+ fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
parcel.write_binder(this)
}
}
impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
impl Deserialize for SpIBinder {
- fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
+ fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
parcel
.read_binder()
.transpose()
@@ -411,19 +439,18 @@
}
impl DeserializeOption for SpIBinder {
- fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> {
+ fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<SpIBinder>> {
parcel.read_binder()
}
}
impl DeserializeArray for SpIBinder {}
-impl DeserializeArray for Option<SpIBinder> {}
/// A weak reference to a Binder remote object.
///
/// This struct encapsulates the generic C++ `wp<IBinder>` class. This wrapper
/// is untyped; typed interface access is implemented by the AIDL compiler.
-pub struct WpIBinder(*mut sys::AIBinder_Weak);
+pub struct WpIBinder(ptr::NonNull<sys::AIBinder_Weak>);
impl fmt::Debug for WpIBinder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -433,9 +460,14 @@
/// # Safety
///
-/// A `WpIBinder` is a handle to a C++ IBinder, which is thread-safe.
+/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
unsafe impl Send for WpIBinder {}
+/// # Safety
+///
+/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+unsafe impl Sync for WpIBinder {}
+
impl WpIBinder {
/// Create a new weak reference from an object that can be converted into a
/// raw `AIBinder` pointer.
@@ -445,8 +477,7 @@
// valid pointer to an `AIBinder`.
sys::AIBinder_Weak_new(binder.as_native_mut())
};
- assert!(!ptr.is_null());
- Self(ptr)
+ Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new"))
}
/// Promote this weak reference to a strong reference to the binder object.
@@ -456,7 +487,7 @@
// can pass this pointer to `AIBinder_Weak_promote`. Returns either
// null or an AIBinder owned by the caller, both of which are valid
// to pass to `SpIBinder::from_raw`.
- let ptr = sys::AIBinder_Weak_promote(self.0);
+ let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr());
SpIBinder::from_raw(ptr)
}
}
@@ -471,13 +502,9 @@
//
// We get ownership of the returned pointer, so can construct a new
// WpIBinder object from it.
- sys::AIBinder_Weak_clone(self.0)
+ sys::AIBinder_Weak_clone(self.0.as_ptr())
};
- assert!(
- !ptr.is_null(),
- "Unexpected null pointer from AIBinder_Weak_clone"
- );
- Self(ptr)
+ Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone"))
}
}
@@ -488,14 +515,14 @@
// so this pointer is always safe to pass to `AIBinder_Weak_lt`
// (null is also safe to pass to this function, but we should never
// do that).
- sys::AIBinder_Weak_lt(self.0, other.0)
+ sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr())
};
let greater_than = unsafe {
// Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
// so this pointer is always safe to pass to `AIBinder_Weak_lt`
// (null is also safe to pass to this function, but we should never
// do that).
- sys::AIBinder_Weak_lt(other.0, self.0)
+ sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr())
};
if !less_than && !greater_than {
Ordering::Equal
@@ -526,16 +553,26 @@
unsafe {
// Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
// know this pointer is safe to pass to `AIBinder_Weak_delete` here.
- sys::AIBinder_Weak_delete(self.0);
+ sys::AIBinder_Weak_delete(self.0.as_ptr());
}
}
}
/// Rust wrapper around DeathRecipient objects.
+///
+/// The cookie in this struct represents an Arc<F> for the owned callback.
+/// This struct owns a ref-count of it, and so does every binder that we
+/// have been linked with.
#[repr(C)]
pub struct DeathRecipient {
recipient: *mut sys::AIBinder_DeathRecipient,
- callback: Box<dyn Fn() + Send + 'static>,
+ cookie: *mut c_void,
+ vtable: &'static DeathRecipientVtable,
+}
+
+struct DeathRecipientVtable {
+ cookie_incr_refcount: unsafe extern "C" fn(*mut c_void),
+ cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
}
impl DeathRecipient {
@@ -543,9 +580,9 @@
/// associated object dies.
pub fn new<F>(callback: F) -> DeathRecipient
where
- F: Fn() + Send + 'static,
+ F: Fn() + Send + Sync + 'static,
{
- let callback = Box::new(callback);
+ let callback: *const F = Arc::into_raw(Arc::new(callback));
let recipient = unsafe {
// Safety: The function pointer is a valid death recipient callback.
//
@@ -554,34 +591,85 @@
// no longer needed.
sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
};
+ unsafe {
+ // Safety: The function pointer is a valid onUnlinked callback.
+ //
+ // All uses of linkToDeath in this file correctly increment the
+ // ref-count that this onUnlinked callback will decrement.
+ sys::AIBinder_DeathRecipient_setOnUnlinked(recipient, Some(Self::cookie_decr_refcount::<F>));
+ }
DeathRecipient {
recipient,
- callback,
+ cookie: callback as *mut c_void,
+ vtable: &DeathRecipientVtable {
+ cookie_incr_refcount: Self::cookie_incr_refcount::<F>,
+ cookie_decr_refcount: Self::cookie_decr_refcount::<F>,
+ },
}
}
+ /// Increment the ref-count for the cookie and return it.
+ ///
+ /// # Safety
+ ///
+ /// The caller must handle the returned ref-count correctly.
+ unsafe fn new_cookie(&self) -> *mut c_void {
+ (self.vtable.cookie_incr_refcount)(self.cookie);
+
+ // Return a raw pointer with ownership of a ref-count
+ self.cookie
+ }
+
/// Get the opaque cookie that identifies this death recipient.
///
/// This cookie will be used to link and unlink this death recipient to a
/// binder object and will be passed to the `binder_died` callback as an
/// opaque userdata pointer.
fn get_cookie(&self) -> *mut c_void {
- &*self.callback as *const _ as *mut c_void
+ self.cookie
}
/// Callback invoked from C++ when the binder object dies.
///
/// # Safety
///
- /// The `cookie` parameter must have been created with the `get_cookie`
- /// method of this object.
+ /// The `cookie` parameter must be the cookie for an Arc<F> and
+ /// the caller must hold a ref-count to it.
unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
where
- F: Fn() + Send + 'static,
+ F: Fn() + Send + Sync + 'static,
{
- let callback = (cookie as *mut F).as_ref().unwrap();
+ let callback = (cookie as *const F).as_ref().unwrap();
callback();
}
+
+ /// Callback that decrements the ref-count.
+ /// This is invoked from C++ when a binder is unlinked.
+ ///
+ /// # Safety
+ ///
+ /// The `cookie` parameter must be the cookie for an Arc<F> and
+ /// the owner must give up a ref-count to it.
+ unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
+ where
+ F: Fn() + Send + Sync + 'static,
+ {
+ drop(Arc::from_raw(cookie as *const F));
+ }
+
+ /// Callback that increments the ref-count.
+ ///
+ /// # Safety
+ ///
+ /// The `cookie` parameter must be the cookie for an Arc<F> and
+ /// the owner must handle the created ref-count properly.
+ unsafe extern "C" fn cookie_incr_refcount<F>(cookie: *mut c_void)
+ where
+ F: Fn() + Send + Sync + 'static,
+ {
+ let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F));
+ mem::forget(Arc::clone(&arc));
+ }
}
/// # Safety
@@ -607,6 +695,12 @@
// `AIBinder_DeathRecipient_new` when `self` was created. This
// delete method can only be called once when `self` is dropped.
sys::AIBinder_DeathRecipient_delete(self.recipient);
+
+ // Safety: We own a ref-count to the cookie, and so does every
+ // linked binder. This call gives up our ref-count. The linked
+ // binders should already have given up their ref-count, or should
+ // do so shortly.
+ (self.vtable.cookie_decr_refcount)(self.cookie)
}
}
}
@@ -653,6 +747,18 @@
}
}
+/// Retrieve an existing service, or start it if it is configured as a dynamic
+/// service and isn't yet started.
+pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
+ let name = CString::new(name).ok()?;
+ unsafe {
+ // Safety: `AServiceManager_waitforService` returns either a null
+ // pointer or a valid pointer to an owned `AIBinder`. Either of these
+ // values is safe to pass to `SpIBinder::from_raw`.
+ SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr()))
+ }
+}
+
/// Retrieve an existing service for a particular interface, blocking for a few
/// seconds if it doesn't yet exist.
pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
@@ -663,16 +769,81 @@
}
}
+/// Retrieve an existing service for a particular interface, or start it if it
+/// is configured as a dynamic service and isn't yet started.
+pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
+ let service = wait_for_service(name);
+ match service {
+ Some(service) => FromIBinder::try_from(service),
+ None => Err(StatusCode::NAME_NOT_FOUND),
+ }
+}
+
+/// Check if a service is declared (e.g. in a VINTF manifest)
+pub fn is_declared(interface: &str) -> Result<bool> {
+ let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+
+ unsafe {
+ // Safety: `interface` is a valid null-terminated C-style string and is
+ // only borrowed for the lifetime of the call. The `interface` local
+ // outlives this call as it lives for the function scope.
+ Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
+ }
+}
+
+/// Retrieve all declared instances for a particular interface
+///
+/// For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo'
+/// is passed here, then ["foo"] would be returned.
+pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
+ unsafe extern "C" fn callback(instance: *const c_char, opaque: *mut c_void) {
+ // Safety: opaque was a mutable pointer created below from a Vec of
+ // CString, and outlives this callback. The null handling here is just
+ // to avoid the possibility of unwinding across C code if this crate is
+ // ever compiled with panic=unwind.
+ if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+ // Safety: instance is a valid null-terminated C string with a
+ // lifetime at least as long as this function, and we immediately
+ // copy it into an owned CString.
+ instances.push(CStr::from_ptr(instance).to_owned());
+ } else {
+ eprintln!("Opaque pointer was null in get_declared_instances callback!");
+ }
+ }
+
+ let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+ let mut instances: Vec<CString> = vec![];
+ unsafe {
+ // Safety: `interface` and `instances` are borrowed for the length of
+ // this call and both outlive the call. `interface` is guaranteed to be
+ // a valid null-terminated C-style string.
+ sys::AServiceManager_forEachDeclaredInstance(
+ interface.as_ptr(),
+ &mut instances as *mut _ as *mut c_void,
+ Some(callback),
+ );
+ }
+
+ instances
+ .into_iter()
+ .map(CString::into_string)
+ .collect::<std::result::Result<Vec<String>, _>>()
+ .map_err(|e| {
+ eprintln!("An interface instance name was not a valid UTF-8 string: {}", e);
+ StatusCode::BAD_VALUE
+ })
+}
+
/// # Safety
///
/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
/// `AIBinder`, so we can trivially extract this pointer here.
unsafe impl AsNative<sys::AIBinder> for SpIBinder {
fn as_native(&self) -> *const sys::AIBinder {
- self.0
+ self.0.as_ptr()
}
fn as_native_mut(&mut self) -> *mut sys::AIBinder {
- self.0
+ self.0.as_ptr()
}
}
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0e05f10..0aef744 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -99,6 +99,17 @@
}
}
+ /// Determine whether the current thread is currently executing an incoming transaction.
+ ///
+ /// \return true if the current thread is currently executing an incoming transaction, and false
+ /// otherwise.
+ pub fn is_handling_transaction() -> bool {
+ unsafe {
+ // Safety: Safe FFI
+ sys::AIBinder_isHandlingTransaction()
+ }
+ }
+
/// This function makes the client's security context available to the
/// service calling this function. This can be used for access control.
/// It does not suffer from the TOCTOU issues of get_calling_pid.
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 607860f..2d1175b 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -13,6 +13,8 @@
rustlibs: [
"libbinder_rs",
"libselinux_bindgen",
+ "libbinder_tokio_rs",
+ "libtokio",
],
shared_libs: [
"libselinux",
@@ -50,7 +52,7 @@
"libbinder_ndk",
],
static_libs: [
- "IBinderRustNdkInteropTest-ndk_platform",
+ "IBinderRustNdkInteropTest-ndk",
"libbinder_ndk_rust_interop",
],
test_suites: ["general-tests"],
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 0332007..c9d6af0 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -16,13 +16,18 @@
//! Rust Binder crate integration tests
-use binder::declare_binder_interface;
-use binder::parcel::Parcel;
-use binder::{
- Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
- FIRST_CALL_TRANSACTION,
+use binder::{declare_binder_enum, declare_binder_interface};
+use binder::{BinderFeatures, Interface, StatusCode, ThreadState};
+// Import from internal API for testing only, do not use this module in
+// production.
+use binder::binder_impl::{
+ Binder, BorrowedParcel, IBinderInternal, TransactionCode, FIRST_CALL_TRANSACTION,
};
+
use std::convert::{TryFrom, TryInto};
+use std::ffi::CStr;
+use std::fs::File;
+use std::sync::Mutex;
/// Name of service runner.
///
@@ -50,13 +55,11 @@
let extension_name = args.next();
{
- let mut service = Binder::new(BnTest(Box::new(TestService {
- s: service_name.clone(),
- })));
+ let mut service = Binder::new(BnTest(Box::new(TestService::new(&service_name))));
service.set_requesting_sid(true);
if let Some(extension_name) = extension_name {
let extension =
- BnTest::new_binder(TestService { s: extension_name }, BinderFeatures::default());
+ BnTest::new_binder(TestService::new(&extension_name), BinderFeatures::default());
service
.set_extension(&mut extension.as_binder())
.expect("Could not add extension");
@@ -80,15 +83,26 @@
));
}
-#[derive(Clone)]
struct TestService {
s: String,
+ dump_args: Mutex<Vec<String>>,
+}
+
+impl TestService {
+ fn new(s: &str) -> Self {
+ Self {
+ s: s.to_string(),
+ dump_args: Mutex::new(Vec::new()),
+ }
+ }
}
#[repr(u32)]
enum TestTransactionCode {
Test = FIRST_CALL_TRANSACTION,
+ GetDumpArgs,
GetSelinuxContext,
+ GetIsHandlingTransaction,
}
impl TryFrom<u32> for TestTransactionCode {
@@ -97,35 +111,73 @@
fn try_from(c: u32) -> Result<Self, Self::Error> {
match c {
_ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
+ _ if c == TestTransactionCode::GetDumpArgs as u32 => Ok(TestTransactionCode::GetDumpArgs),
_ if c == TestTransactionCode::GetSelinuxContext as u32 => {
Ok(TestTransactionCode::GetSelinuxContext)
}
+ _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => Ok(TestTransactionCode::GetIsHandlingTransaction),
_ => Err(StatusCode::UNKNOWN_TRANSACTION),
}
}
}
-impl Interface for TestService {}
+impl Interface for TestService {
+ fn dump(&self, _file: &File, args: &[&CStr]) -> Result<(), StatusCode> {
+ let mut dump_args = self.dump_args.lock().unwrap();
+ dump_args.extend(args.iter().map(|s| s.to_str().unwrap().to_owned()));
+ Ok(())
+ }
+}
impl ITest for TestService {
- fn test(&self) -> binder::Result<String> {
+ fn test(&self) -> Result<String, StatusCode> {
Ok(self.s.clone())
}
- fn get_selinux_context(&self) -> binder::Result<String> {
+ fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
+ let args = self.dump_args.lock().unwrap().clone();
+ Ok(args)
+ }
+
+ fn get_selinux_context(&self) -> Result<String, StatusCode> {
let sid =
ThreadState::with_calling_sid(|sid| sid.map(|s| s.to_string_lossy().into_owned()));
sid.ok_or(StatusCode::UNEXPECTED_NULL)
}
+
+ fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
+ Ok(binder::is_handling_transaction())
+ }
}
/// Trivial testing binder interface
pub trait ITest: Interface {
/// Returns a test string
- fn test(&self) -> binder::Result<String>;
+ fn test(&self) -> Result<String, StatusCode>;
+
+ /// Return the arguments sent via dump
+ fn get_dump_args(&self) -> Result<Vec<String>, StatusCode>;
/// Returns the caller's SELinux context
- fn get_selinux_context(&self) -> binder::Result<String>;
+ fn get_selinux_context(&self) -> Result<String, StatusCode>;
+
+ /// Returns the value of calling `is_handling_transaction`.
+ fn get_is_handling_transaction(&self) -> Result<bool, StatusCode>;
+}
+
+/// Async trivial testing binder interface
+pub trait IATest<P>: Interface {
+ /// Returns a test string
+ fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>;
+
+ /// Return the arguments sent via dump
+ fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>>;
+
+ /// Returns the caller's SELinux context
+ fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>;
+
+ /// Returns the value of calling `is_handling_transaction`.
+ fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>>;
}
declare_binder_interface! {
@@ -134,30 +186,40 @@
proxy: BpTest {
x: i32 = 100
},
+ async: IATest,
}
}
fn on_transact(
service: &dyn ITest,
code: TransactionCode,
- _data: &Parcel,
- reply: &mut Parcel,
-) -> binder::Result<()> {
+ _data: &BorrowedParcel<'_>,
+ reply: &mut BorrowedParcel<'_>,
+) -> Result<(), StatusCode> {
match code.try_into()? {
TestTransactionCode::Test => reply.write(&service.test()?),
+ TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
+ TestTransactionCode::GetIsHandlingTransaction => reply.write(&service.get_is_handling_transaction()?),
}
}
impl ITest for BpTest {
- fn test(&self) -> binder::Result<String> {
+ fn test(&self) -> Result<String, StatusCode> {
let reply =
self.binder
.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
reply.read()
}
- fn get_selinux_context(&self) -> binder::Result<String> {
+ fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
+ let reply =
+ self.binder
+ .transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))?;
+ reply.read()
+ }
+
+ fn get_selinux_context(&self) -> Result<String, StatusCode> {
let reply = self.binder.transact(
TestTransactionCode::GetSelinuxContext as TransactionCode,
0,
@@ -165,16 +227,89 @@
)?;
reply.read()
}
+
+ fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
+ let reply = self.binder.transact(
+ TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
+ 0,
+ |_| Ok(()),
+ )?;
+ reply.read()
+ }
+}
+
+impl<P: binder::BinderAsyncPool> IATest<P> for BpTest {
+ fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
+ )
+ }
+
+ fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
+ )
+ }
+
+ fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
+ )
+ }
+
+ fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
+ let binder = self.binder.clone();
+ P::spawn(
+ move || binder.transact(TestTransactionCode::GetIsHandlingTransaction as TransactionCode, 0, |_| Ok(())),
+ |reply| async move { reply?.read() }
+ )
+ }
}
impl ITest for Binder<BnTest> {
- fn test(&self) -> binder::Result<String> {
+ fn test(&self) -> Result<String, StatusCode> {
self.0.test()
}
- fn get_selinux_context(&self) -> binder::Result<String> {
+ fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
+ self.0.get_dump_args()
+ }
+
+ fn get_selinux_context(&self) -> Result<String, StatusCode> {
self.0.get_selinux_context()
}
+
+ fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
+ self.0.get_is_handling_transaction()
+ }
+}
+
+impl<P: binder::BinderAsyncPool> IATest<P> for Binder<BnTest> {
+ fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
+ let res = self.0.test();
+ Box::pin(async move { res })
+ }
+
+ fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
+ let res = self.0.get_dump_args();
+ Box::pin(async move { res })
+ }
+
+ fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
+ let res = self.0.get_selinux_context();
+ Box::pin(async move { res })
+ }
+
+ fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
+ let res = self.0.get_is_handling_transaction();
+ Box::pin(async move { res })
+ }
}
/// Trivial testing binder interface
@@ -190,9 +325,9 @@
fn on_transact_same_descriptor(
_service: &dyn ITestSameDescriptor,
_code: TransactionCode,
- _data: &Parcel,
- _reply: &mut Parcel,
-) -> binder::Result<()> {
+ _data: &BorrowedParcel<'_>,
+ _reply: &mut BorrowedParcel<'_>,
+) -> Result<(), StatusCode> {
Ok(())
}
@@ -200,6 +335,23 @@
impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
+declare_binder_enum! {
+ TestEnum : [i32; 3] {
+ FOO = 1,
+ BAR = 2,
+ BAZ = 3,
+ }
+}
+
+declare_binder_enum! {
+ #[deprecated(since = "1.0.0")]
+ TestDeprecatedEnum : [i32; 3] {
+ FOO = 1,
+ BAR = 2,
+ BAZ = 3,
+ }
+}
+
#[cfg(test)]
mod tests {
use selinux_bindgen as selinux_sys;
@@ -213,11 +365,16 @@
use std::time::Duration;
use binder::{
- Binder, BinderFeatures, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface,
- SpIBinder, StatusCode, Strong,
+ BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode,
+ Strong,
};
+ // Import from impl API for testing only, should not be necessary as long as
+ // you are using AIDL.
+ use binder::binder_impl::{Binder, IBinderInternal, TransactionCode};
- use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+ use binder_tokio::Tokio;
+
+ use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
pub struct ScopedServiceProcess(Child);
@@ -265,12 +422,80 @@
binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
Some(StatusCode::NAME_NOT_FOUND)
);
+ assert_eq!(
+ binder::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
// The service manager service isn't an ITest, so this must fail.
assert_eq!(
binder::get_interface::<dyn ITest>("manager").err(),
Some(StatusCode::BAD_TYPE)
);
+ assert_eq!(
+ binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ }
+
+ #[tokio::test]
+ async fn check_services_async() {
+ let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
+ assert!(sm.is_binder_alive());
+ assert!(sm.ping_binder().is_ok());
+
+ assert!(binder::get_service("this_service_does_not_exist").is_none());
+ assert_eq!(
+ binder_tokio::get_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
+ assert_eq!(
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+ Some(StatusCode::NAME_NOT_FOUND)
+ );
+
+ // The service manager service isn't an ITest, so this must fail.
+ assert_eq!(
+ binder_tokio::get_interface::<dyn ITest>("manager").await.err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ assert_eq!(
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("manager").await.err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ }
+
+ #[test]
+ fn check_wait_for_service() {
+ let mut sm =
+ binder::wait_for_service("manager").expect("Did not get manager binder service");
+ assert!(sm.is_binder_alive());
+ assert!(sm.ping_binder().is_ok());
+
+ // The service manager service isn't an ITest, so this must fail.
+ assert_eq!(
+ binder::wait_for_interface::<dyn ITest>("manager").err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ assert_eq!(
+ binder::wait_for_interface::<dyn IATest<Tokio>>("manager").err(),
+ Some(StatusCode::BAD_TYPE)
+ );
+ }
+
+ #[test]
+ fn get_declared_instances() {
+ // At the time of writing this test, there is no good VINTF interface
+ // guaranteed to be on all devices. Cuttlefish has light, so this will
+ // generally test things.
+ let has_lights = binder::is_declared("android.hardware.light.ILights/default")
+ .expect("Could not check for declared interface");
+
+ let instances = binder::get_declared_instances("android.hardware.light.ILights")
+ .expect("Could not get declared instances");
+
+ let expected_defaults = if has_lights { 1 } else { 0 };
+ assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
}
#[test]
@@ -282,33 +507,146 @@
assert_eq!(test_client.test().unwrap(), "trivial_client_test");
}
+ #[tokio::test]
+ async fn trivial_client_async() {
+ let service_name = "trivial_client_test";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
+ }
+
+ #[test]
+ fn wait_for_trivial_client() {
+ let service_name = "wait_for_trivial_client_test";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn ITest> =
+ binder::wait_for_interface(service_name).expect("Did not get manager binder service");
+ assert_eq!(test_client.test().unwrap(), "wait_for_trivial_client_test");
+ }
+
+ #[tokio::test]
+ async fn wait_for_trivial_client_async() {
+ let service_name = "wait_for_trivial_client_test";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+ assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
+ }
+
+ fn get_expected_selinux_context() -> &'static str {
+ unsafe {
+ let mut out_ptr = ptr::null_mut();
+ assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
+ assert!(!out_ptr.is_null());
+ CStr::from_ptr(out_ptr)
+ .to_str()
+ .expect("context was invalid UTF-8")
+ }
+ }
+
#[test]
fn get_selinux_context() {
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
- let expected_context = unsafe {
- let mut out_ptr = ptr::null_mut();
- assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
- assert!(!out_ptr.is_null());
- CStr::from_ptr(out_ptr)
- };
assert_eq!(
test_client.get_selinux_context().unwrap(),
- expected_context
- .to_str()
- .expect("context was invalid UTF-8"),
+ get_expected_selinux_context()
);
}
- fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
+ #[tokio::test]
+ async fn get_selinux_context_async() {
+ let service_name = "get_selinux_context_async";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ assert_eq!(
+ test_client.get_selinux_context().await.unwrap(),
+ get_expected_selinux_context()
+ );
+ }
+
+ #[tokio::test]
+ async fn get_selinux_context_sync_to_async() {
+ let service_name = "get_selinux_context";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn ITest> =
+ binder::get_interface(service_name).expect("Did not get manager binder service");
+ let test_client = test_client.into_async::<Tokio>();
+ assert_eq!(
+ test_client.get_selinux_context().await.unwrap(),
+ get_expected_selinux_context()
+ );
+ }
+
+ #[tokio::test]
+ async fn get_selinux_context_async_to_sync() {
+ let service_name = "get_selinux_context";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client = test_client.into_sync();
+ assert_eq!(
+ test_client.get_selinux_context().unwrap(),
+ get_expected_selinux_context()
+ );
+ }
+
+ struct Bools {
+ binder_died: Arc<AtomicBool>,
+ binder_dealloc: Arc<AtomicBool>,
+ }
+
+ impl Bools {
+ fn is_dead(&self) -> bool {
+ self.binder_died.load(Ordering::Relaxed)
+ }
+ fn assert_died(&self) {
+ assert!(
+ self.is_dead(),
+ "Did not receive death notification"
+ );
+ }
+ fn assert_dropped(&self) {
+ assert!(
+ self.binder_dealloc.load(Ordering::Relaxed),
+ "Did not dealloc death notification"
+ );
+ }
+ fn assert_not_dropped(&self) {
+ assert!(
+ !self.binder_dealloc.load(Ordering::Relaxed),
+ "Dealloc death notification too early"
+ );
+ }
+ }
+
+ fn register_death_notification(binder: &mut SpIBinder) -> (Bools, DeathRecipient) {
let binder_died = Arc::new(AtomicBool::new(false));
+ let binder_dealloc = Arc::new(AtomicBool::new(false));
+
+ struct SetOnDrop {
+ binder_dealloc: Arc<AtomicBool>,
+ }
+ impl Drop for SetOnDrop {
+ fn drop(&mut self) {
+ self.binder_dealloc.store(true, Ordering::Relaxed);
+ }
+ }
let mut death_recipient = {
let flag = binder_died.clone();
+ let set_on_drop = SetOnDrop {
+ binder_dealloc: binder_dealloc.clone(),
+ };
DeathRecipient::new(move || {
flag.store(true, Ordering::Relaxed);
+ // Force the closure to take ownership of set_on_drop. When the closure is
+ // dropped, the destructor of `set_on_drop` will run.
+ let _ = &set_on_drop;
})
};
@@ -316,7 +654,12 @@
.link_to_death(&mut death_recipient)
.expect("link_to_death failed");
- (binder_died, death_recipient)
+ let bools = Bools {
+ binder_died,
+ binder_dealloc,
+ };
+
+ (bools, death_recipient)
}
/// Killing a remote service should unregister the service and trigger
@@ -329,7 +672,7 @@
let service_process = ScopedServiceProcess::new(service_name);
let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
- let (binder_died, _recipient) = register_death_notification(&mut remote);
+ let (bools, recipient) = register_death_notification(&mut remote);
drop(service_process);
remote
@@ -339,10 +682,12 @@
// Pause to ensure any death notifications get delivered
thread::sleep(Duration::from_secs(1));
- assert!(
- binder_died.load(Ordering::Relaxed),
- "Did not receive death notification"
- );
+ bools.assert_died();
+ bools.assert_not_dropped();
+
+ drop(recipient);
+
+ bools.assert_dropped();
}
/// Test unregistering death notifications.
@@ -354,7 +699,7 @@
let service_process = ScopedServiceProcess::new(service_name);
let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
- let (binder_died, mut recipient) = register_death_notification(&mut remote);
+ let (bools, mut recipient) = register_death_notification(&mut remote);
remote
.unlink_to_death(&mut recipient)
@@ -369,9 +714,13 @@
thread::sleep(Duration::from_secs(1));
assert!(
- !binder_died.load(Ordering::Relaxed),
+ !bools.is_dead(),
"Received unexpected death notification after unlinking",
);
+
+ bools.assert_not_dropped();
+ drop(recipient);
+ bools.assert_dropped();
}
/// Dropping a remote handle should unregister any death notifications.
@@ -383,7 +732,7 @@
let service_process = ScopedServiceProcess::new(service_name);
let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
- let (binder_died, _recipient) = register_death_notification(&mut remote);
+ let (bools, recipient) = register_death_notification(&mut remote);
// This should automatically unregister our death notification.
drop(remote);
@@ -396,9 +745,13 @@
// We dropped the remote handle, so we should not receive the death
// notification when the remote process dies here.
assert!(
- !binder_died.load(Ordering::Relaxed),
+ !bools.is_dead(),
"Received unexpected death notification after dropping remote handle"
);
+
+ bools.assert_not_dropped();
+ drop(recipient);
+ bools.assert_dropped();
}
/// Test IBinder interface methods not exercised elsewhere.
@@ -409,18 +762,21 @@
{
let _process = ScopedServiceProcess::new(service_name);
- let mut remote = binder::get_service(service_name);
+ let test_client: Strong<dyn ITest> =
+ binder::get_interface(service_name).expect("Did not get test binder service");
+ let mut remote = test_client.as_binder();
assert!(remote.is_binder_alive());
remote.ping_binder().expect("Could not ping remote service");
- // We're not testing the output of dump here, as that's really a
- // property of the C++ implementation. There is the risk that the
- // method just does nothing, but we don't want to depend on any
- // particular output from the underlying library.
+ let dump_args = ["dump", "args", "for", "testing"];
+
let null_out = File::open("/dev/null").expect("Could not open /dev/null");
remote
- .dump(&null_out, &[])
+ .dump(&null_out, &dump_args)
.expect("Could not dump remote service");
+
+ let remote_args = test_client.get_dump_args().expect("Could not fetched dumped args");
+ assert_eq!(dump_args, remote_args[..], "Remote args don't match call to dump");
}
// get/set_extensions is tested in test_extensions()
@@ -481,9 +837,7 @@
/// rust_ndk_interop.rs
#[test]
fn associate_existing_class() {
- let service = Binder::new(BnTest(Box::new(TestService {
- s: "testing_service".to_string(),
- })));
+ let service = Binder::new(BnTest(Box::new(TestService::new("testing_service"))));
// This should succeed although we will have to treat the service as
// remote.
@@ -497,9 +851,7 @@
fn reassociate_rust_binder() {
let service_name = "testing_service";
let service_ibinder = BnTest::new_binder(
- TestService {
- s: service_name.to_string(),
- },
+ TestService::new(service_name),
BinderFeatures::default(),
)
.as_binder();
@@ -515,9 +867,7 @@
fn weak_binder_upgrade() {
let service_name = "testing_service";
let service = BnTest::new_binder(
- TestService {
- s: service_name.to_string(),
- },
+ TestService::new(service_name),
BinderFeatures::default(),
);
@@ -533,9 +883,7 @@
let service_name = "testing_service";
let weak = {
let service = BnTest::new_binder(
- TestService {
- s: service_name.to_string(),
- },
+ TestService::new(service_name),
BinderFeatures::default(),
);
@@ -549,9 +897,7 @@
fn weak_binder_clone() {
let service_name = "testing_service";
let service = BnTest::new_binder(
- TestService {
- s: service_name.to_string(),
- },
+ TestService::new(service_name),
BinderFeatures::default(),
);
@@ -570,20 +916,80 @@
#[allow(clippy::eq_op)]
fn binder_ord() {
let service1 = BnTest::new_binder(
- TestService {
- s: "testing_service1".to_string(),
- },
+ TestService::new("testing_service1"),
BinderFeatures::default(),
);
let service2 = BnTest::new_binder(
- TestService {
- s: "testing_service2".to_string(),
- },
+ TestService::new("testing_service2"),
BinderFeatures::default(),
);
- assert!(!(service1 < service1));
- assert!(!(service1 > service1));
- assert_eq!(service1 < service2, !(service2 < service1));
+ assert!((service1 >= service1));
+ assert!((service1 <= service1));
+ assert_eq!(service1 < service2, (service2 >= service1));
+ }
+
+ #[test]
+ fn binder_parcel_mixup() {
+ let service1 = BnTest::new_binder(
+ TestService::new("testing_service1"),
+ BinderFeatures::default(),
+ );
+ let service2 = BnTest::new_binder(
+ TestService::new("testing_service2"),
+ BinderFeatures::default(),
+ );
+
+ let service1 = service1.as_binder();
+ let service2 = service2.as_binder();
+
+ let parcel = service1.prepare_transact().unwrap();
+ let res = service2.submit_transact(super::TestTransactionCode::Test as TransactionCode, parcel, 0);
+
+ match res {
+ Ok(_) => panic!("submit_transact should fail"),
+ Err(err) => assert_eq!(err, binder::StatusCode::BAD_VALUE),
+ }
+ }
+
+ #[test]
+ fn get_is_handling_transaction() {
+ let service_name = "get_is_handling_transaction";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn ITest> =
+ binder::get_interface(service_name).expect("Did not get manager binder service");
+ // Should be true externally.
+ assert!(test_client.get_is_handling_transaction().unwrap());
+
+ // Should be false locally.
+ assert!(!binder::is_handling_transaction());
+
+ // Should also be false in spawned thread.
+ std::thread::spawn(|| {
+ assert!(!binder::is_handling_transaction());
+ }).join().unwrap();
+ }
+
+ #[tokio::test]
+ async fn get_is_handling_transaction_async() {
+ let service_name = "get_is_handling_transaction_async";
+ let _process = ScopedServiceProcess::new(service_name);
+ let test_client: Strong<dyn IATest<Tokio>> =
+ binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ // Should be true externally.
+ assert!(test_client.get_is_handling_transaction().await.unwrap());
+
+ // Should be false locally.
+ assert!(!binder::is_handling_transaction());
+
+ // Should also be false in spawned task.
+ tokio::spawn(async {
+ assert!(!binder::is_handling_transaction());
+ }).await.unwrap();
+
+ // And in spawn_blocking task.
+ tokio::task::spawn_blocking(|| {
+ assert!(!binder::is_handling_transaction());
+ }).await.unwrap();
}
}
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 4702e45..415ede1 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -90,7 +90,7 @@
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, BinderFeatures::default());
- match binder::add_service(&service_name, service.as_binder()) {
+ 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 66ba846..b62da7b 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -18,11 +18,12 @@
//! access.
use binder::declare_binder_interface;
-use binder::parcel::ParcelFileDescriptor;
use binder::{
- Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
- StatusCode, TransactionCode,
+ BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, SpIBinder, Status, StatusCode,
};
+// Import from impl API for testing only, should not be necessary as long as you
+// are using AIDL.
+use binder::binder_impl::{BorrowedParcel, Binder, TransactionCode};
use std::ffi::{c_void, CStr, CString};
use std::sync::Once;
@@ -111,9 +112,9 @@
fn on_transact(
_service: &dyn ReadParcelTest,
code: TransactionCode,
- parcel: &Parcel,
- reply: &mut Parcel,
-) -> Result<()> {
+ parcel: &BorrowedParcel<'_>,
+ reply: &mut BorrowedParcel<'_>,
+) -> Result<(), StatusCode> {
match code {
bindings::Transaction_TEST_BOOL => {
assert_eq!(parcel.read::<bool>()?, true);
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
new file mode 100644
index 0000000..777f3c9
--- /dev/null
+++ b/libs/binder/servicedispatcher.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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 <sysexits.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android/debug/BnAdbCallback.h>
+#include <android/debug/IAdbManager.h>
+#include <android/os/BnServiceManager.h>
+#include <android/os/IServiceManager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcServer.h>
+
+using android::BBinder;
+using android::defaultServiceManager;
+using android::OK;
+using android::RpcServer;
+using android::sp;
+using android::status_t;
+using android::statusToString;
+using android::String16;
+using android::base::Basename;
+using android::base::GetBoolProperty;
+using android::base::InitLogging;
+using android::base::LogdLogger;
+using android::base::LogId;
+using android::base::LogSeverity;
+using android::base::StdioLogger;
+using android::base::StringPrintf;
+using std::string_view_literals::operator""sv;
+
+namespace {
+
+const char* kLocalInetAddress = "127.0.0.1";
+using ServiceRetriever = decltype(&android::IServiceManager::checkService);
+using android::debug::IAdbManager;
+
+int Usage(const char* program) {
+ auto basename = Basename(program);
+ auto format = R"(dispatch calls to RPC service.
+Usage:
+ %s [-g] <service_name>
+ <service_name>: the service to connect to.
+ %s [-g] manager
+ Runs an RPC-friendly service that redirects calls to servicemanager.
+
+ -g: use getService() instead of checkService().
+
+ If successful, writes port number and a new line character to stdout, and
+ blocks until killed.
+ Otherwise, writes error message to stderr and exits with non-zero code.
+)";
+ LOG(ERROR) << StringPrintf(format, basename.c_str(), basename.c_str());
+ return EX_USAGE;
+}
+
+int Dispatch(const char* name, const ServiceRetriever& serviceRetriever) {
+ auto sm = defaultServiceManager();
+ if (nullptr == sm) {
+ LOG(ERROR) << "No servicemanager";
+ return EX_SOFTWARE;
+ }
+ auto binder = std::invoke(serviceRetriever, defaultServiceManager(), String16(name));
+ if (nullptr == binder) {
+ LOG(ERROR) << "No service \"" << name << "\"";
+ return EX_SOFTWARE;
+ }
+ auto rpcServer = RpcServer::make();
+ if (nullptr == rpcServer) {
+ LOG(ERROR) << "Cannot create RpcServer";
+ return EX_SOFTWARE;
+ }
+ unsigned int port;
+ if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+ LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
+ return EX_SOFTWARE;
+ }
+ auto socket = rpcServer->releaseServer();
+ auto keepAliveBinder = sp<BBinder>::make();
+ auto status = binder->setRpcClientDebug(std::move(socket), keepAliveBinder);
+ if (status != OK) {
+ LOG(ERROR) << "setRpcClientDebug failed with " << statusToString(status);
+ return EX_SOFTWARE;
+ }
+ LOG(INFO) << "Finish setting up RPC on service " << name << " on port " << port;
+
+ std::cout << port << std::endl;
+
+ TEMP_FAILURE_RETRY(pause());
+
+ PLOG(FATAL) << "TEMP_FAILURE_RETRY(pause()) exits; this should not happen!";
+ __builtin_unreachable();
+}
+
+// Wrapper that wraps a BpServiceManager as a BnServiceManager.
+class ServiceManagerProxyToNative : public android::os::BnServiceManager {
+public:
+ ServiceManagerProxyToNative(const sp<android::os::IServiceManager>& impl) : mImpl(impl) {}
+ android::binder::Status getService(const std::string&,
+ android::sp<android::IBinder>*) override {
+ // We can't send BpBinder for regular binder over RPC.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status checkService(const std::string&,
+ android::sp<android::IBinder>*) override {
+ // We can't send BpBinder for regular binder over RPC.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status addService(const std::string&, const android::sp<android::IBinder>&,
+ bool, int32_t) override {
+ // We can't send BpBinder for RPC over regular binder.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status listServices(int32_t dumpPriority,
+ std::vector<std::string>* _aidl_return) override {
+ return mImpl->listServices(dumpPriority, _aidl_return);
+ }
+ android::binder::Status registerForNotifications(
+ const std::string&, const android::sp<android::os::IServiceCallback>&) override {
+ // We can't send BpBinder for RPC over regular binder.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status unregisterForNotifications(
+ const std::string&, const android::sp<android::os::IServiceCallback>&) override {
+ // We can't send BpBinder for RPC over regular binder.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status isDeclared(const std::string& name, bool* _aidl_return) override {
+ return mImpl->isDeclared(name, _aidl_return);
+ }
+ android::binder::Status getDeclaredInstances(const std::string& iface,
+ std::vector<std::string>* _aidl_return) override {
+ return mImpl->getDeclaredInstances(iface, _aidl_return);
+ }
+ android::binder::Status updatableViaApex(const std::string& name,
+ std::optional<std::string>* _aidl_return) override {
+ return mImpl->updatableViaApex(name, _aidl_return);
+ }
+ android::binder::Status getConnectionInfo(
+ const std::string& name,
+ std::optional<android::os::ConnectionInfo>* _aidl_return) override {
+ return mImpl->getConnectionInfo(name, _aidl_return);
+ }
+ android::binder::Status registerClientCallback(
+ const std::string&, const android::sp<android::IBinder>&,
+ const android::sp<android::os::IClientCallback>&) override {
+ // We can't send BpBinder for RPC over regular binder.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status tryUnregisterService(const std::string&,
+ const android::sp<android::IBinder>&) override {
+ // We can't send BpBinder for RPC over regular binder.
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ android::binder::Status getServiceDebugInfo(
+ std::vector<android::os::ServiceDebugInfo>* _aidl_return) override {
+ return mImpl->getServiceDebugInfo(_aidl_return);
+ }
+
+private:
+ sp<android::os::IServiceManager> mImpl;
+};
+
+// Workaround for b/191059588.
+// TODO(b/191059588): Once we can run RpcServer on single-threaded services,
+// `servicedispatcher manager` should call Dispatch("manager") directly.
+int wrapServiceManager(const ServiceRetriever& serviceRetriever) {
+ auto sm = defaultServiceManager();
+ if (nullptr == sm) {
+ LOG(ERROR) << "No servicemanager";
+ return EX_SOFTWARE;
+ }
+ auto service = std::invoke(serviceRetriever, defaultServiceManager(), String16("manager"));
+ if (nullptr == service) {
+ LOG(ERROR) << "No service called `manager`";
+ return EX_SOFTWARE;
+ }
+ auto interface = android::os::IServiceManager::asInterface(service);
+ if (nullptr == interface) {
+ LOG(ERROR) << "Cannot cast service called `manager` to IServiceManager";
+ return EX_SOFTWARE;
+ }
+
+ // Work around restriction that doesn't allow us to send proxy over RPC.
+ interface = sp<ServiceManagerProxyToNative>::make(interface);
+ service = ServiceManagerProxyToNative::asBinder(interface);
+
+ auto rpcServer = RpcServer::make();
+ rpcServer->setRootObject(service);
+ unsigned int port;
+ if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+ LOG(ERROR) << "Unable to set up inet server: " << statusToString(status);
+ return EX_SOFTWARE;
+ }
+ LOG(INFO) << "Finish wrapping servicemanager with RPC on port " << port;
+ std::cout << port << std::endl;
+ rpcServer->join();
+
+ LOG(FATAL) << "Wrapped servicemanager exits; this should not happen!";
+ __builtin_unreachable();
+}
+
+class AdbCallback : public android::debug::BnAdbCallback {
+public:
+ android::binder::Status onDebuggingChanged(bool enabled,
+ android::debug::AdbTransportType) override {
+ if (!enabled) {
+ LOG(ERROR) << "ADB debugging disabled, exiting.";
+ exit(EX_SOFTWARE);
+ }
+ return android::binder::Status::ok();
+ }
+};
+
+void exitOnAdbDebuggingDisabled() {
+ auto adb = android::waitForService<IAdbManager>(String16("adb"));
+ CHECK(adb != nullptr) << "Unable to retrieve service adb";
+ auto status = adb->registerCallback(sp<AdbCallback>::make());
+ CHECK(status.isOk()) << "Unable to call IAdbManager::registerCallback: " << status;
+}
+
+// Log to logd. For warning and more severe messages, also log to stderr.
+class ServiceDispatcherLogger {
+public:
+ void operator()(LogId id, LogSeverity severity, const char* tag, const char* file,
+ unsigned int line, const char* message) {
+ mLogdLogger(id, severity, tag, file, line, message);
+ if (severity >= LogSeverity::WARNING) {
+ std::cout << std::flush;
+ std::cerr << Basename(getprogname()) << ": " << message << std::endl;
+ }
+ }
+
+private:
+ LogdLogger mLogdLogger{};
+};
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ InitLogging(argv, ServiceDispatcherLogger());
+
+ if (!GetBoolProperty("ro.debuggable", false)) {
+ LOG(ERROR) << "servicedispatcher is only allowed on debuggable builds.";
+ return EX_NOPERM;
+ }
+ LOG(WARNING) << "WARNING: servicedispatcher is debug only. Use with caution.";
+
+ int opt;
+ ServiceRetriever serviceRetriever = &android::IServiceManager::checkService;
+ while (-1 != (opt = getopt(argc, argv, "g"))) {
+ switch (opt) {
+ case 'g': {
+ serviceRetriever = &android::IServiceManager::getService;
+ } break;
+ default: {
+ return Usage(argv[0]);
+ }
+ }
+ }
+
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ android::ProcessState::self()->startThreadPool();
+ exitOnAdbDebuggingDisabled();
+
+ if (optind + 1 != argc) return Usage(argv[0]);
+ auto name = argv[optind];
+
+ if (name == "manager"sv) {
+ return wrapServiceManager(serviceRetriever);
+ }
+ return Dispatch(name, serviceRetriever);
+}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index d584897..a3533d8 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -37,7 +37,11 @@
srcs: ["binderDriverInterfaceTest.cpp"],
header_libs: ["libbinder_headers"],
compile_multilib: "32",
- multilib: { lib32: { suffix: "" } },
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ },
cflags: ["-DBINDER_IPC_32BIT=1"],
test_suites: ["vts"],
}
@@ -52,7 +56,10 @@
},
header_libs: ["libbinder_headers"],
srcs: ["binderDriverInterfaceTest.cpp"],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
}
cc_test {
@@ -60,14 +67,20 @@
defaults: ["binder_test_defaults"],
srcs: ["binderLibTest.cpp"],
shared_libs: [
+ "libbase",
"libbinder",
+ "liblog",
"libutils",
],
static_libs: [
"libgmock",
],
compile_multilib: "32",
- multilib: { lib32: { suffix: "" } },
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ },
cflags: ["-DBINDER_IPC_32BIT=1"],
test_suites: ["vts"],
require_root: true,
@@ -75,16 +88,22 @@
// unit test only, which can run on host and doesn't use /dev/binder
cc_test {
- name: "binderParcelTest",
+ name: "binderUnitTest",
host_supported: true,
target: {
darwin: {
enabled: false,
},
},
- srcs: ["binderParcelTest.cpp"],
+ srcs: [
+ "binderParcelUnitTest.cpp",
+ "binderBinderUnitTest.cpp",
+ "binderStatusUnitTest.cpp",
+ "binderMemoryHeapBaseUnitTest.cpp",
+ ],
shared_libs: [
"libbinder",
+ "libcutils",
"libutils",
],
test_suites: ["general-tests"],
@@ -101,13 +120,18 @@
srcs: ["binderLibTest.cpp"],
shared_libs: [
+ "libbase",
"libbinder",
+ "liblog",
"libutils",
],
static_libs: [
"libgmock",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -116,8 +140,12 @@
host_supported: true,
unstable: true,
srcs: [
+ "BinderRpcTestClientInfo.aidl",
+ "BinderRpcTestServerInfo.aidl",
+ "IBinderRpcCallback.aidl",
"IBinderRpcSession.aidl",
"IBinderRpcTest.aidl",
+ "ParcelableCertificateData.aidl",
],
backend: {
java: {
@@ -126,6 +154,37 @@
},
}
+cc_library_static {
+ name: "libbinder_tls_test_utils",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ defaults: [
+ "binder_test_defaults",
+ "libbinder_tls_shared_deps",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "liblog",
+ ],
+ static_libs: [
+ "libbinder_tls_static",
+ ],
+ srcs: [
+ "RpcTlsTestUtils.cpp",
+ ],
+ export_include_dirs: [
+ "include_tls_test_utils",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
cc_test {
name: "binderRpcTest",
host_supported: true,
@@ -133,10 +192,13 @@
darwin: {
enabled: false,
},
+ android: {
+ test_suites: ["vts"],
+ },
},
defaults: [
"binder_test_defaults",
- "libbinder_ndk_host_user",
+ "libbinder_tls_shared_deps",
],
srcs: [
@@ -151,19 +213,55 @@
"liblog",
],
static_libs: [
+ "libbinder_tls_static",
+ "libbinder_tls_test_utils",
"binderRpcTestIface-cpp",
- "binderRpcTestIface-ndk_platform",
+ "binderRpcTestIface-ndk",
],
+ test_suites: ["general-tests"],
require_root: true,
- // Prevent the unit test target from running on sc-dev as it's not ready.
- test_options: {
- unit_test: false,
+}
+
+cc_test {
+ name: "RpcTlsUtilsTest",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ android: {
+ test_suites: ["vts"],
+ },
},
+ defaults: [
+ "binder_test_defaults",
+ "libbinder_tls_shared_deps",
+ ],
+ srcs: [
+ "RpcTlsUtilsTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "libutils",
+ "liblog",
+ ],
+ static_libs: [
+ "libbinder_tls_test_utils",
+ "libbinder_tls_static",
+ ],
+ test_suites: [
+ "general-tests",
+ "device-tests",
+ ],
}
cc_benchmark {
name: "binderRpcBenchmark",
- defaults: ["binder_test_defaults"],
+ defaults: [
+ "binder_test_defaults",
+ "libbinder_tls_shared_deps",
+ ],
host_supported: true,
target: {
darwin: {
@@ -180,6 +278,37 @@
"liblog",
"libutils",
],
+ static_libs: [
+ "libbinder_tls_test_utils",
+ "libbinder_tls_static",
+ ],
+}
+
+cc_test {
+ name: "binderRpcWireProtocolTest",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ android: {
+ test_suites: ["vts"],
+ },
+ },
+ defaults: [
+ "binder_test_defaults",
+ ],
+ srcs: [
+ "binderRpcWireProtocolTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "liblog",
+ ],
+ test_suites: ["general-tests"],
}
cc_test {
@@ -240,7 +369,10 @@
"liblog",
"libutils",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -291,10 +423,13 @@
],
static_libs: [
"binderStabilityTestIface-cpp",
- "binderStabilityTestIface-ndk_platform",
+ "binderStabilityTestIface-ndk",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -324,3 +459,68 @@
"libutils",
],
}
+
+cc_test_host {
+ name: "binderUtilsHostTest",
+ defaults: ["binder_test_defaults"],
+ srcs: ["binderUtilsHostTest.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ test_suites: ["general-tests"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test_host {
+ name: "binderHostDeviceTest",
+ defaults: ["binder_test_defaults"],
+ srcs: ["binderHostDeviceTest.cpp"],
+ test_config: "binderHostDeviceTest.xml",
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ target_required: [
+ "binderHostDeviceTestService",
+ ],
+ test_suites: ["general-tests"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ test_options: {
+ unit_test: false,
+ },
+}
+
+cc_test {
+ name: "binderHostDeviceTestService",
+ // The binary is named differently from the module so that PushFilePreparer pushes the binary
+ // directly, not the test module directory.
+ stem: "binderHostDeviceTest-service",
+ defaults: ["binder_test_defaults"],
+ gtest: false,
+ auto_gen_config: false,
+ srcs: ["binderHostDeviceTestService.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/libs/binder/tests/BinderRpcTestClientInfo.aidl b/libs/binder/tests/BinderRpcTestClientInfo.aidl
new file mode 100644
index 0000000..b4baebc
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestClientInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+import ParcelableCertificateData;
+
+parcelable BinderRpcTestClientInfo {
+ ParcelableCertificateData[] certs;
+}
diff --git a/libs/binder/tests/BinderRpcTestServerInfo.aidl b/libs/binder/tests/BinderRpcTestServerInfo.aidl
new file mode 100644
index 0000000..00dc0bc
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestServerInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+import ParcelableCertificateData;
+
+parcelable BinderRpcTestServerInfo {
+ long port;
+ ParcelableCertificateData cert;
+}
diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl
index 1457422..2baf680 100644
--- a/libs/binder/tests/IBinderRpcBenchmark.aidl
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -17,4 +17,5 @@
interface IBinderRpcBenchmark {
@utf8InCpp String repeatString(@utf8InCpp String str);
IBinder repeatBinder(IBinder binder);
+ byte[] repeatBytes(in byte[] bytes);
}
diff --git a/libs/binder/tests/IBinderRpcCallback.aidl b/libs/binder/tests/IBinderRpcCallback.aidl
new file mode 100644
index 0000000..0336961
--- /dev/null
+++ b/libs/binder/tests/IBinderRpcCallback.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+interface IBinderRpcCallback {
+ void sendCallback(@utf8InCpp String str);
+ oneway void sendOnewayCallback(@utf8InCpp String str);
+}
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index ef4198d..fdd02a4 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -18,6 +18,9 @@
oneway void sendString(@utf8InCpp String str);
@utf8InCpp String doubleString(@utf8InCpp String str);
+ // get the port that a client used to connect to this object
+ int getClientPort();
+
// number of known RPC binders to process, RpcState::countBinders by session
int[] countBinders();
@@ -54,5 +57,11 @@
void sleepMs(int ms);
oneway void sleepMsAsync(int ms);
+ void doCallback(IBinderRpcCallback callback, boolean isOneway, boolean delayed, @utf8InCpp String value);
+ oneway void doCallbackAsync(IBinderRpcCallback callback, boolean isOneway, boolean delayed, @utf8InCpp String value);
+
void die(boolean cleanup);
+ void scheduleShutdown();
+
+ void useKernelBinderCallingId();
}
diff --git a/libs/binder/tests/ParcelableCertificateData.aidl b/libs/binder/tests/ParcelableCertificateData.aidl
new file mode 100644
index 0000000..38c382e
--- /dev/null
+++ b/libs/binder/tests/ParcelableCertificateData.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+parcelable ParcelableCertificateData {
+ byte[] data;
+}
diff --git a/libs/binder/tests/RpcTlsTestUtils.cpp b/libs/binder/tests/RpcTlsTestUtils.cpp
new file mode 100644
index 0000000..6119313
--- /dev/null
+++ b/libs/binder/tests/RpcTlsTestUtils.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcTlsTestUtils"
+#include <log/log.h>
+
+#include <binder/RpcTlsTestUtils.h>
+
+#include <binder/RpcTlsUtils.h>
+
+#include "../Utils.h" // for TEST_AND_RETURN
+
+namespace android {
+
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
+ bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
+ ALOGE("Failed to generate key pair.");
+ return nullptr;
+ }
+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+ // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
+ // the refcount of the ec_key, so it is okay to release it at the end of this function.
+ if (pkey == nullptr || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) {
+ ALOGE("Failed to assign key pair.");
+ return nullptr;
+ }
+ return pkey;
+}
+
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pkey, const uint32_t validSeconds) {
+ bssl::UniquePtr<X509> x509(X509_new());
+ bssl::UniquePtr<BIGNUM> serial(BN_new());
+ bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
+ TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
+ TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
+ TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
+ TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
+ TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notAfter(x509.get()), validSeconds));
+
+ X509_NAME* subject = X509_get_subject_name(x509.get());
+ TEST_AND_RETURN(nullptr,
+ X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>("Android"), -1, -1,
+ 0));
+ TEST_AND_RETURN(nullptr,
+ X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
+ -1, 0));
+ TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
+
+ TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), pkey));
+ TEST_AND_RETURN(nullptr, X509_sign(x509.get(), pkey, EVP_sha256()));
+ return x509;
+}
+
+status_t RpcAuthSelfSigned::configure(SSL_CTX* ctx) {
+ auto pkey = makeKeyPairForSelfSignedCert();
+ TEST_AND_RETURN(UNKNOWN_ERROR, pkey != nullptr);
+ auto cert = makeSelfSignedCert(pkey.get(), mValidSeconds);
+ TEST_AND_RETURN(UNKNOWN_ERROR, cert != nullptr);
+ TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_PrivateKey(ctx, pkey.get()));
+ TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_certificate(ctx, cert.get()));
+ return OK;
+}
+
+status_t RpcAuthPreSigned::configure(SSL_CTX* ctx) {
+ if (!SSL_CTX_use_PrivateKey(ctx, mPkey.get())) {
+ return INVALID_OPERATION;
+ }
+ if (!SSL_CTX_use_certificate(ctx, mCert.get())) {
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t RpcCertificateVerifierSimple::verify(const SSL* ssl, uint8_t* outAlert) {
+ const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+ bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
+ "%s: libssl should not ask to verify non-existing cert", logPrefix);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (const auto& trustedCert : mTrustedPeerCertificates) {
+ if (0 == X509_cmp(trustedCert.get(), peerCert.get())) {
+ return OK;
+ }
+ }
+ *outAlert = SSL_AD_CERTIFICATE_UNKNOWN;
+ return PERMISSION_DENIED;
+}
+
+status_t RpcCertificateVerifierSimple::addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert) {
+ bssl::UniquePtr<X509> x509 = deserializeCertificate(cert, format);
+ if (x509 == nullptr) {
+ ALOGE("Certificate is not in the proper format %s", PrintToString(format).c_str());
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTrustedPeerCertificates.push_back(std::move(x509));
+ return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/RpcTlsUtilsTest.cpp b/libs/binder/tests/RpcTlsUtilsTest.cpp
new file mode 100644
index 0000000..530606c
--- /dev/null
+++ b/libs/binder/tests/RpcTlsUtilsTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+std::string toDebugString(EVP_PKEY* pkey) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ int res = EVP_PKEY_print_public(bio.get(), pkey, 2, nullptr);
+ std::string buf = "\nEVP_PKEY_print_public -> " + std::to_string(res) + "\n";
+ if (BIO_write(bio.get(), buf.data(), buf.length()) <= 0) return {};
+ res = EVP_PKEY_print_private(bio.get(), pkey, 2, nullptr);
+ buf = "\nEVP_PKEY_print_private -> " + std::to_string(res);
+ if (BIO_write(bio.get(), buf.data(), buf.length()) <= 0) return {};
+ const uint8_t* data;
+ size_t len;
+ if (!BIO_mem_contents(bio.get(), &data, &len)) return {};
+ return std::string(reinterpret_cast<const char*>(data), len);
+}
+
+class RpcTlsUtilsKeyTest : public testing::TestWithParam<RpcKeyFormat> {
+public:
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ return PrintToString(info.param);
+ }
+};
+
+TEST_P(RpcTlsUtilsKeyTest, Test) {
+ auto pkey = makeKeyPairForSelfSignedCert();
+ ASSERT_NE(nullptr, pkey);
+ auto pkeyData = serializeUnencryptedPrivatekey(pkey.get(), GetParam());
+ auto deserializedPkey = deserializeUnencryptedPrivatekey(pkeyData, GetParam());
+ ASSERT_NE(nullptr, deserializedPkey);
+ EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), deserializedPkey.get()))
+ << "expected: " << toDebugString(pkey.get())
+ << "\nactual: " << toDebugString(deserializedPkey.get());
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsKeyTest,
+ testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+ RpcTlsUtilsKeyTest::PrintParamInfo);
+
+class RpcTlsUtilsCertTest : public testing::TestWithParam<RpcCertificateFormat> {
+public:
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ return PrintToString(info.param);
+ }
+};
+
+TEST_P(RpcTlsUtilsCertTest, Test) {
+ auto pkey = makeKeyPairForSelfSignedCert();
+ ASSERT_NE(nullptr, pkey);
+ // Make certificate from the original key in memory
+ auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
+ ASSERT_NE(nullptr, cert);
+ auto certData = serializeCertificate(cert.get(), GetParam());
+ auto deserializedCert = deserializeCertificate(certData, GetParam());
+ ASSERT_NE(nullptr, deserializedCert);
+ EXPECT_EQ(0, X509_cmp(cert.get(), deserializedCert.get()));
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsCertTest,
+ testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
+ RpcTlsUtilsCertTest::PrintParamInfo);
+
+class RpcTlsUtilsKeyAndCertTest
+ : public testing::TestWithParam<std::tuple<RpcKeyFormat, RpcCertificateFormat>> {
+public:
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [keyFormat, certificateFormat] = info.param;
+ return "key_" + PrintToString(keyFormat) + "_cert_" + PrintToString(certificateFormat);
+ }
+};
+
+TEST_P(RpcTlsUtilsKeyAndCertTest, TestCertFromDeserializedKey) {
+ auto [keyFormat, certificateFormat] = GetParam();
+ auto pkey = makeKeyPairForSelfSignedCert();
+ ASSERT_NE(nullptr, pkey);
+ auto pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
+ auto deserializedPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
+ ASSERT_NE(nullptr, deserializedPkey);
+
+ // Make certificate from deserialized key loaded from bytes
+ auto cert = makeSelfSignedCert(deserializedPkey.get(), kCertValidSeconds);
+ ASSERT_NE(nullptr, cert);
+ auto certData = serializeCertificate(cert.get(), certificateFormat);
+ auto deserializedCert = deserializeCertificate(certData, certificateFormat);
+ ASSERT_NE(nullptr, deserializedCert);
+ EXPECT_EQ(0, X509_cmp(cert.get(), deserializedCert.get()));
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsKeyAndCertTest,
+ testing::Combine(testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+ testing::Values(RpcCertificateFormat::PEM,
+ RpcCertificateFormat::DER)),
+ RpcTlsUtilsKeyAndCertTest::PrintParamInfo);
+
+} // namespace android
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
new file mode 100644
index 0000000..ce2770f
--- /dev/null
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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/Binder.h>
+#include <binder/IBinder.h>
+#include <gtest/gtest.h>
+
+using android::BBinder;
+using android::OK;
+using android::sp;
+
+const void* kObjectId1 = reinterpret_cast<const void*>(1);
+const void* kObjectId2 = reinterpret_cast<const void*>(2);
+void* kObject1 = reinterpret_cast<void*>(101);
+void* kObject2 = reinterpret_cast<void*>(102);
+void* kObject3 = reinterpret_cast<void*>(103);
+
+TEST(Binder, AttachObject) {
+ auto binder = sp<BBinder>::make();
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject1, nullptr, nullptr));
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId2, kObject2, nullptr, nullptr));
+ EXPECT_EQ(kObject1, binder->attachObject(kObjectId1, kObject3, nullptr, nullptr));
+}
+
+TEST(Binder, DetachObject) {
+ auto binder = sp<BBinder>::make();
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject1, nullptr, nullptr));
+ EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
+}
+
+TEST(Binder, AttachExtension) {
+ auto binder = sp<BBinder>::make();
+ auto ext = sp<BBinder>::make();
+ binder->setExtension(ext);
+ EXPECT_EQ(ext, binder->getExtension());
+}
diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp
index 2d30c8d..307151c 100644
--- a/libs/binder/tests/binderClearBufTest.cpp
+++ b/libs/binder/tests/binderClearBufTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
@@ -30,22 +31,6 @@
const String16 kServerName = String16("binderClearBuf");
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- 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;
-}
-
class FooBar : public BBinder {
public:
enum {
@@ -83,7 +68,7 @@
lastReply = reply.data();
lastReplySize = reply.dataSize();
}
- *outBuffer = hexString(lastReply, lastReplySize);
+ *outBuffer = android::base::HexString(lastReply, lastReplySize);
return result;
}
};
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
new file mode 100644
index 0000000..464da60
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+// Integration test for servicedispatcher + adb forward. Requires ADB.
+
+#include <stdlib.h>
+
+#include <vector>
+
+#include <android-base/parsebool.h>
+#include <android-base/result-gmock.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "../UtilsHost.h"
+
+using ::android::setDefaultServiceManager;
+using ::android::base::EndsWith;
+using ::android::base::Join;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
+using ::android::base::Split;
+using ::android::base::StartsWith;
+using ::android::base::StringReplace;
+using ::android::base::Trim;
+using ::android::base::testing::Ok;
+using ::std::chrono_literals::operator""ms;
+using ::std::string_literals::operator""s;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::ContainsRegex;
+using ::testing::ExplainMatchResult;
+using ::testing::InitGoogleMock;
+
+namespace android {
+
+namespace {
+
+constexpr const char* kServiceBinary = "/data/local/tmp/binderHostDeviceTest-service";
+constexpr const char* kServiceName = "binderHostDeviceTestService";
+constexpr const char* kDescriptor = "android.binderHostDeviceTestService";
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+ *result_listener << statusToString(arg);
+ return expected == arg;
+}
+
+void initHostRpcServiceManagerOnce() {
+ static std::once_flag gSmOnce;
+ std::call_once(gSmOnce, [] {
+ setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
+ });
+}
+
+// Test for host service manager.
+class HostDeviceTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ auto debuggableResult = execute(Split("adb shell getprop ro.debuggable", " "), nullptr);
+ ASSERT_THAT(debuggableResult, Ok());
+ ASSERT_EQ(0, debuggableResult->exitCode) << *debuggableResult;
+ auto debuggableBool = ParseBool(Trim(debuggableResult->stdoutStr));
+ ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdoutStr);
+ if (debuggableBool == ParseBoolResult::kFalse) {
+ GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdoutStr);
+ }
+
+ auto lsResult = execute(Split("adb shell which servicedispatcher", " "), nullptr);
+ ASSERT_THAT(lsResult, Ok());
+ if (lsResult->exitCode != 0) {
+ GTEST_SKIP() << "b/182914638: until feature is fully enabled, skip test on devices "
+ "without servicedispatcher";
+ }
+
+ initHostRpcServiceManagerOnce();
+ ASSERT_NE(nullptr, defaultServiceManager()) << "No defaultServiceManager() over RPC";
+
+ auto service = execute({"adb", "shell", kServiceBinary, kServiceName, kDescriptor},
+ &CommandResult::stdoutEndsWithNewLine);
+ ASSERT_THAT(service, Ok());
+ ASSERT_EQ(std::nullopt, service->exitCode) << *service;
+ mService = std::move(*service);
+ }
+ void TearDown() override { mService.reset(); }
+
+ [[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
+ auto rpcSession = RpcSession::make();
+ if (status_t status = rpcSession->setupInetClient("127.0.0.1", hostPort); status != OK) {
+ ADD_FAILURE() << "Failed to setupInetClient on " << hostPort << ": "
+ << statusToString(status);
+ return nullptr;
+ }
+ return rpcSession->getRootObject();
+ }
+
+private:
+ std::optional<CommandResult> mService;
+};
+
+TEST_F(HostDeviceTest, List) {
+ auto sm = defaultServiceManager();
+
+ auto services = sm->listServices();
+ ASSERT_THAT(services, Contains(String16(kServiceName)));
+}
+
+TEST_F(HostDeviceTest, CheckService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->checkService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, GetService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->getService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, WaitForService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->waitForService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, TenClients) {
+ auto sm = defaultServiceManager();
+
+ auto threadFn = [&] {
+ auto rpcBinder = sm->checkService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+ };
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < 10; ++i) threads.emplace_back(threadFn);
+ for (auto& thread : threads) thread.join();
+}
+
+} // namespace
+
+} // namespace android
diff --git a/libs/binder/tests/binderHostDeviceTest.xml b/libs/binder/tests/binderHostDeviceTest.xml
new file mode 100644
index 0000000..250ed3a
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs binderHostDeviceTest.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="binderHostDeviceTest-service"
+ value="/data/local/tmp/binderHostDeviceTest-service"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest">
+ <option name="binary" value="binderHostDeviceTest"/>
+ </test>
+</configuration>
diff --git a/libs/binder/tests/binderHostDeviceTestService.cpp b/libs/binder/tests/binderHostDeviceTestService.cpp
new file mode 100644
index 0000000..6ddd2e7
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTestService.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <sysexits.h>
+
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+namespace {
+class Service : public android::BBinder {
+public:
+ Service(std::string_view descriptor) : mDescriptor(descriptor.data(), descriptor.size()) {}
+ const android::String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+private:
+ android::String16 mDescriptor;
+};
+} // namespace
+
+int main(int argc, char** argv) {
+ if (argc != 3) {
+ std::cerr << "usage: " << argv[0] << " <service-name> <interface-descriptor>" << std::endl;
+ return EX_USAGE;
+ }
+ auto name = argv[1];
+ auto descriptor = argv[2];
+
+ auto sm = android::defaultServiceManager();
+ CHECK(sm != nullptr);
+ auto service = android::sp<Service>::make(descriptor);
+ auto status = sm->addService(android::String16(name), service);
+ CHECK_EQ(android::OK, status) << android::statusToString(status);
+ std::cout << "running..." << std::endl;
+ android::ProcessState::self()->startThreadPool();
+ android::IPCThreadState::self()->joinThreadPool();
+ LOG(ERROR) << "joinThreadPool exits";
+ return EX_SOFTWARE;
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 6cb7e7f..b1e17b7 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -15,25 +15,36 @@
*/
#include <errno.h>
-#include <fcntl.h>
-#include <fstream>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
+
+#include <chrono>
+#include <fstream>
#include <thread>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <android-base/properties.h>
+#include <android-base/result-gmock.h>
+#include <android-base/result.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <binder/Binder.h>
+#include <binder/BpBinder.h>
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
#include <linux/sched.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include "../binder_module.h"
#include "binderAbiHelper.h"
@@ -41,7 +52,14 @@
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
using namespace android;
+using namespace std::string_literals;
+using namespace std::chrono_literals;
+using android::base::testing::HasValue;
+using android::base::testing::Ok;
+using testing::ExplainMatchResult;
+using testing::Matcher;
using testing::Not;
+using testing::WithParamInterface;
// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
@@ -72,6 +90,7 @@
BINDER_LIB_TEST_REGISTER_SERVER,
BINDER_LIB_TEST_ADD_SERVER,
BINDER_LIB_TEST_ADD_POLL_SERVER,
+ BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION,
BINDER_LIB_TEST_CALL_BACK,
BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
BINDER_LIB_TEST_DELAYED_CALL_BACK,
@@ -156,6 +175,20 @@
return pid;
}
+android::base::Result<int32_t> GetId(sp<IBinder> service) {
+ using android::base::Error;
+ Parcel data, reply;
+ data.markForBinder(service);
+ const char *prefix = data.isForRpc() ? "On RPC server, " : "On binder server, ";
+ status_t status = service->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply);
+ if (status != OK)
+ return Error(status) << prefix << "transact(GET_ID): " << statusToString(status);
+ int32_t result = 0;
+ status = reply.readInt32(&result);
+ if (status != OK) return Error(status) << prefix << "readInt32: " << statusToString(status);
+ return result;
+}
+
class BinderLibTestEnv : public ::testing::Environment {
public:
BinderLibTestEnv() {}
@@ -404,6 +437,19 @@
};
};
+TEST_F(BinderLibTest, CannotUseBinderAfterFork) {
+ // EXPECT_DEATH works by forking the process
+ EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork");
+}
+
+TEST_F(BinderLibTest, WasParceled) {
+ auto binder = sp<BBinder>::make();
+ EXPECT_FALSE(binder->wasParceled());
+ Parcel data;
+ data.writeStrongBinder(binder);
+ EXPECT_TRUE(binder->wasParceled());
+}
+
TEST_F(BinderLibTest, NopTransaction) {
Parcel data, reply;
EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply),
@@ -451,7 +497,7 @@
EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, true, 1000));
EXPECT_EQ(FAILED_TRANSACTION, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
- bool sync_received, async_received;
+ uint32_t sync_received, async_received;
EXPECT_EQ(NO_ERROR, IPCThreadState::self()->getProcessFreezeInfo(pid, &sync_received,
&async_received));
@@ -459,15 +505,7 @@
EXPECT_EQ(sync_received, 1);
EXPECT_EQ(async_received, 0);
- uint32_t sync_received2, async_received2;
-
- EXPECT_EQ(NO_ERROR, IPCThreadState::self()->getProcessFreezeInfo(pid, &sync_received2,
- &async_received2));
-
- EXPECT_EQ(sync_received2, 1);
- EXPECT_EQ(async_received2, 0);
-
- EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 0, 0));
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0));
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
}
@@ -482,12 +520,7 @@
}
TEST_F(BinderLibTest, GetId) {
- int32_t id;
- Parcel data, reply;
- EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply),
- StatusEq(NO_ERROR));
- EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
- EXPECT_EQ(0, id);
+ EXPECT_THAT(GetId(m_server), HasValue(0));
}
TEST_F(BinderLibTest, PtrSize) {
@@ -610,6 +643,13 @@
EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR));
}
+TEST_F(BinderLibTest, BinderCallContextGuard) {
+ sp<IBinder> binder = addServer();
+ Parcel data, reply;
+ EXPECT_THAT(binder->transact(BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION, data, &reply),
+ StatusEq(DEAD_OBJECT));
+}
+
TEST_F(BinderLibTest, AddServer)
{
sp<IBinder> server = addServer();
@@ -1181,39 +1221,142 @@
EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
}
-class BinderLibTestService : public BBinder
-{
- public:
- explicit BinderLibTestService(int32_t id)
- : m_id(id)
- , m_nextServerId(id + 1)
- , m_serverStartRequested(false)
- , m_callback(nullptr)
- {
- pthread_mutex_init(&m_serverWaitMutex, nullptr);
- pthread_cond_init(&m_serverWaitCond, nullptr);
- }
- ~BinderLibTestService()
- {
- exit(EXIT_SUCCESS);
- }
+TEST(ServiceNotifications, Unregister) {
+ auto sm = defaultServiceManager();
+ using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+ class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback {
+ void onServiceRegistration(const String16 &, const sp<IBinder> &) override {}
+ virtual ~LocalRegistrationCallbackImpl() {}
+ };
+ sp<LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make();
- void processPendingCall() {
- if (m_callback != nullptr) {
- Parcel data;
- data.writeInt32(NO_ERROR);
- m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY);
- m_callback = nullptr;
- }
- }
+ EXPECT_EQ(sm->registerForNotifications(String16("RogerRafa"), cb), OK);
+ EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK);
+}
- virtual status_t onTransact(uint32_t code,
- const Parcel& data, Parcel* reply,
- uint32_t flags = 0) {
- if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) {
- return PERMISSION_DENIED;
- }
- switch (code) {
+class BinderLibRpcTestBase : public BinderLibTest {
+public:
+ void SetUp() override {
+ if (!base::GetBoolProperty("ro.debuggable", false)) {
+ GTEST_SKIP() << "Binder RPC is only enabled on debuggable builds, skipping test on "
+ "non-debuggable builds.";
+ }
+ BinderLibTest::SetUp();
+ }
+
+ std::tuple<android::base::unique_fd, unsigned int> CreateSocket() {
+ auto rpcServer = RpcServer::make();
+ EXPECT_NE(nullptr, rpcServer);
+ if (rpcServer == nullptr) return {};
+ unsigned int port;
+ if (status_t status = rpcServer->setupInetServer("127.0.0.1", 0, &port); status != OK) {
+ ADD_FAILURE() << "setupInetServer failed" << statusToString(status);
+ return {};
+ }
+ return {rpcServer->releaseServer(), port};
+ }
+};
+
+class BinderLibRpcTest : public BinderLibRpcTestBase {};
+
+// e.g. EXPECT_THAT(expr, Debuggable(StatusEq(...))
+// If device is debuggable AND not on user builds, expects matcher.
+// Otherwise expects INVALID_OPERATION.
+// Debuggable + non user builds is necessary but not sufficient for setRpcClientDebug to work.
+static Matcher<status_t> Debuggable(const Matcher<status_t> &matcher) {
+ bool isDebuggable = android::base::GetBoolProperty("ro.debuggable", false) &&
+ android::base::GetProperty("ro.build.type", "") != "user";
+ return isDebuggable ? matcher : StatusEq(INVALID_OPERATION);
+}
+
+TEST_F(BinderLibRpcTest, SetRpcClientDebug) {
+ auto binder = addServer();
+ ASSERT_TRUE(binder != nullptr);
+ auto [socket, port] = CreateSocket();
+ ASSERT_TRUE(socket.ok());
+ EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), sp<BBinder>::make()),
+ Debuggable(StatusEq(OK)));
+}
+
+// Tests for multiple RpcServer's on the same binder object.
+TEST_F(BinderLibRpcTest, SetRpcClientDebugTwice) {
+ auto binder = addServer();
+ ASSERT_TRUE(binder != nullptr);
+
+ auto [socket1, port1] = CreateSocket();
+ ASSERT_TRUE(socket1.ok());
+ auto keepAliveBinder1 = sp<BBinder>::make();
+ EXPECT_THAT(binder->setRpcClientDebug(std::move(socket1), keepAliveBinder1),
+ Debuggable(StatusEq(OK)));
+
+ auto [socket2, port2] = CreateSocket();
+ ASSERT_TRUE(socket2.ok());
+ auto keepAliveBinder2 = sp<BBinder>::make();
+ EXPECT_THAT(binder->setRpcClientDebug(std::move(socket2), keepAliveBinder2),
+ Debuggable(StatusEq(OK)));
+}
+
+// Negative tests for RPC APIs on IBinder. Call should fail in the same way on both remote and
+// local binders.
+class BinderLibRpcTestP : public BinderLibRpcTestBase, public WithParamInterface<bool> {
+public:
+ sp<IBinder> GetService() {
+ return GetParam() ? sp<IBinder>(addServer()) : sp<IBinder>(sp<BBinder>::make());
+ }
+ static std::string ParamToString(const testing::TestParamInfo<ParamType> &info) {
+ return info.param ? "remote" : "local";
+ }
+};
+
+TEST_P(BinderLibRpcTestP, SetRpcClientDebugNoFd) {
+ auto binder = GetService();
+ ASSERT_TRUE(binder != nullptr);
+ EXPECT_THAT(binder->setRpcClientDebug(android::base::unique_fd(), sp<BBinder>::make()),
+ Debuggable(StatusEq(BAD_VALUE)));
+}
+
+TEST_P(BinderLibRpcTestP, SetRpcClientDebugNoKeepAliveBinder) {
+ auto binder = GetService();
+ ASSERT_TRUE(binder != nullptr);
+ auto [socket, port] = CreateSocket();
+ ASSERT_TRUE(socket.ok());
+ EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), nullptr),
+ Debuggable(StatusEq(UNEXPECTED_NULL)));
+}
+INSTANTIATE_TEST_CASE_P(BinderLibTest, BinderLibRpcTestP, testing::Bool(),
+ BinderLibRpcTestP::ParamToString);
+
+class BinderLibTestService : public BBinder {
+public:
+ explicit BinderLibTestService(int32_t id, bool exitOnDestroy = true)
+ : m_id(id),
+ m_nextServerId(id + 1),
+ m_serverStartRequested(false),
+ m_callback(nullptr),
+ m_exitOnDestroy(exitOnDestroy) {
+ pthread_mutex_init(&m_serverWaitMutex, nullptr);
+ pthread_cond_init(&m_serverWaitCond, nullptr);
+ }
+ ~BinderLibTestService() {
+ if (m_exitOnDestroy) exit(EXIT_SUCCESS);
+ }
+
+ void processPendingCall() {
+ if (m_callback != nullptr) {
+ Parcel data;
+ data.writeInt32(NO_ERROR);
+ m_callback->transact(BINDER_LIB_TEST_CALL_BACK, data, nullptr, TF_ONE_WAY);
+ m_callback = nullptr;
+ }
+ }
+
+ virtual status_t onTransact(uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0) {
+ // TODO(b/182914638): also checks getCallingUid() for RPC
+ if (!data.isForRpc() && getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) {
+ return PERMISSION_DENIED;
+ }
+ switch (code) {
case BINDER_LIB_TEST_REGISTER_SERVER: {
int32_t id;
sp<IBinder> binder;
@@ -1223,8 +1366,7 @@
return BAD_VALUE;
}
- if (m_id != 0)
- return INVALID_OPERATION;
+ if (m_id != 0) return INVALID_OPERATION;
pthread_mutex_lock(&m_serverWaitMutex);
if (m_serverStartRequested) {
@@ -1278,6 +1420,21 @@
pthread_mutex_unlock(&m_serverWaitMutex);
return ret;
}
+ case BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION: {
+ IPCThreadState::SpGuard spGuard{
+ .address = __builtin_frame_address(0),
+ .context = "GuardInBinderTransaction",
+ };
+ const IPCThreadState::SpGuard *origGuard =
+ IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
+ // if the guard works, this should abort
+ (void)IPCThreadState::self()->getCallingPid();
+
+ IPCThreadState::self()->restoreGetCallingSpGuard(origGuard);
+ return NO_ERROR;
+ }
+
case BINDER_LIB_TEST_GETPID:
reply->writeInt32(getpid());
return NO_ERROR;
@@ -1394,8 +1551,7 @@
return BAD_VALUE;
}
ret = target->linkToDeath(testDeathRecipient);
- if (ret == NO_ERROR)
- ret = testDeathRecipient->waitEvent(5);
+ if (ret == NO_ERROR) ret = testDeathRecipient->waitEvent(5);
data2.writeInt32(ret);
callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2);
return NO_ERROR;
@@ -1419,8 +1575,7 @@
return BAD_VALUE;
}
ret = write(fd, buf, size);
- if (ret != size)
- return UNKNOWN_ERROR;
+ if (ret != size) return UNKNOWN_ERROR;
return NO_ERROR;
}
case BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION: {
@@ -1475,8 +1630,7 @@
case BINDER_LIB_TEST_ECHO_VECTOR: {
std::vector<uint64_t> vector;
auto err = data.readUint64Vector(&vector);
- if (err != NO_ERROR)
- return err;
+ if (err != NO_ERROR) return err;
reply->writeUint64Vector(vector);
return NO_ERROR;
}
@@ -1488,23 +1642,33 @@
}
default:
return UNKNOWN_TRANSACTION;
- };
- }
- private:
- int32_t m_id;
- int32_t m_nextServerId;
- pthread_mutex_t m_serverWaitMutex;
- pthread_cond_t m_serverWaitCond;
- bool m_serverStartRequested;
- sp<IBinder> m_serverStarted;
- sp<IBinder> m_strongRef;
- sp<IBinder> m_callback;
+ };
+ }
+
+private:
+ int32_t m_id;
+ int32_t m_nextServerId;
+ pthread_mutex_t m_serverWaitMutex;
+ pthread_cond_t m_serverWaitCond;
+ bool m_serverStartRequested;
+ sp<IBinder> m_serverStarted;
+ sp<IBinder> m_strongRef;
+ sp<IBinder> m_callback;
+ bool m_exitOnDestroy;
};
int run_server(int index, int readypipefd, bool usePoll)
{
binderLibTestServiceName += String16(binderserversuffix);
+ // Testing to make sure that calls that we are serving can use getCallin*
+ // even though we don't here.
+ IPCThreadState::SpGuard spGuard{
+ .address = __builtin_frame_address(0),
+ .context = "main server thread",
+ };
+ (void)IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
status_t ret;
sp<IServiceManager> sm = defaultServiceManager();
BinderLibTestService* testServicePtr;
diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
new file mode 100644
index 0000000..21cb70b
--- /dev/null
+++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 <binder/MemoryHeapBase.h>
+#include <cutils/ashmem.h>
+#include <fcntl.h>
+
+#include <gtest/gtest.h>
+using namespace android;
+#ifdef __BIONIC__
+TEST(MemoryHeapBase, ForceMemfdRespected) {
+ auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_FALSE(ashmem_valid(fd));
+ EXPECT_NE(fcntl(fd, F_GET_SEALS), -1);
+}
+
+TEST(MemoryHeapBase, MemfdSealed) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealed) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0);
+}
+
+TEST(MemoryHeapBase, MemfdSealedProtected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE);
+}
+
+TEST(MemoryHeapBase, MemfdUnsealedProtected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE);
+}
+
+#else
+TEST(MemoryHeapBase, HostMemfdExpected) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::READ_ONLY,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ void* ptr = mHeap->getBase();
+ EXPECT_NE(ptr, MAP_FAILED);
+ EXPECT_TRUE(ashmem_valid(fd));
+ EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+}
+
+TEST(MemoryHeapBase,HostMemfdException) {
+ auto mHeap = sp<MemoryHeapBase>::make(8192,
+ MemoryHeapBase::FORCE_MEMFD |
+ MemoryHeapBase::READ_ONLY |
+ MemoryHeapBase::MEMFD_ALLOW_SEALING,
+ "Test mapping");
+ int fd = mHeap->getHeapID();
+ void* ptr = mHeap->getBase();
+ EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY);
+ EXPECT_TRUE(ashmem_valid(fd));
+ EXPECT_NE(ptr, MAP_FAILED);
+}
+
+#endif
diff --git a/libs/binder/tests/binderParcelTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
similarity index 71%
rename from libs/binder/tests/binderParcelTest.cpp
rename to libs/binder/tests/binderParcelUnitTest.cpp
index 841d47b..359c783 100644
--- a/libs/binder/tests/binderParcelTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -14,16 +14,22 @@
* limitations under the License.
*/
-#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <binder/Status.h>
+#include <cutils/ashmem.h>
#include <gtest/gtest.h>
+using android::BBinder;
+using android::IBinder;
using android::IPCThreadState;
using android::OK;
using android::Parcel;
+using android::sp;
+using android::status_t;
using android::String16;
using android::String8;
-using android::status_t;
+using android::binder::Status;
TEST(Parcel, NonNullTerminatedString8) {
String8 kTestString = String8("test-is-good");
@@ -59,6 +65,53 @@
EXPECT_EQ(output.size(), 0);
}
+TEST(Parcel, EnforceNoDataAvail) {
+ const int32_t kTestInt = 42;
+ const String8 kTestString = String8("test-is-good");
+ Parcel p;
+ p.writeInt32(kTestInt);
+ p.writeString8(kTestString);
+ p.setDataPosition(0);
+ EXPECT_EQ(kTestInt, p.readInt32());
+ EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_BAD_PARCELABLE);
+ EXPECT_EQ(kTestString, p.readString8());
+ EXPECT_EQ(p.enforceNoDataAvail().exceptionCode(), Status::Exception::EX_NONE);
+}
+
+TEST(Parcel, DebugReadAllBinders) {
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ sp<IBinder> binder2 = sp<BBinder>::make();
+
+ Parcel p;
+ p.writeInt32(4);
+ p.writeStrongBinder(binder1);
+ p.writeStrongBinder(nullptr);
+ p.writeInt32(4);
+ p.writeStrongBinder(binder2);
+ p.writeInt32(4);
+
+ auto ret = p.debugReadAllStrongBinders();
+
+ ASSERT_EQ(ret.size(), 2);
+ EXPECT_EQ(ret[0], binder1);
+ EXPECT_EQ(ret[1], binder2);
+}
+
+TEST(Parcel, DebugReadAllFds) {
+ Parcel p;
+ p.writeInt32(4);
+ p.writeFileDescriptor(STDOUT_FILENO, false /*takeOwnership*/);
+ p.writeInt32(4);
+ p.writeFileDescriptor(STDIN_FILENO, false /*takeOwnership*/);
+ p.writeInt32(4);
+
+ auto ret = p.debugReadAllFileDescriptors();
+
+ ASSERT_EQ(ret.size(), 2);
+ EXPECT_EQ(ret[0], STDOUT_FILENO);
+ EXPECT_EQ(ret[1], STDIN_FILENO);
+}
+
// Tests a second operation results in a parcel at the same location as it
// started.
void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
@@ -146,3 +199,18 @@
TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1});
TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")});
TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")});
+
+TEST(Parcel, GetOpenAshmemSize) {
+ constexpr size_t kSize = 1024;
+ constexpr size_t kCount = 3;
+
+ Parcel p;
+
+ for (size_t i = 0; i < kCount; i++) {
+ int fd = ashmem_create_region("test-getOpenAshmemSize", kSize);
+ ASSERT_GE(fd, 0);
+ ASSERT_EQ(OK, p.writeFileDescriptor(fd, true /* take ownership */));
+
+ ASSERT_EQ((kSize * (i + 1)), p.getOpenAshmemSize());
+ }
+}
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index a457e67..52ba9b0 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -18,21 +18,47 @@
#include <android-base/logging.h>
#include <benchmark/benchmark.h>
#include <binder/Binder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcCertificateVerifier.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
+#include <openssl/ssl.h>
#include <thread>
+#include <signal.h>
+#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
using android::BBinder;
+using android::defaultServiceManager;
using android::IBinder;
using android::interface_cast;
+using android::IPCThreadState;
+using android::IServiceManager;
using android::OK;
+using android::ProcessState;
+using android::RpcAuthPreSigned;
+using android::RpcCertificateFormat;
+using android::RpcCertificateVerifier;
+using android::RpcCertificateVerifierNoOp;
using android::RpcServer;
using android::RpcSession;
+using android::RpcTransportCtxFactory;
+using android::RpcTransportCtxFactoryRaw;
+using android::RpcTransportCtxFactoryTls;
using android::sp;
+using android::status_t;
+using android::statusToString;
+using android::String16;
using android::binder::Status;
class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
@@ -40,34 +66,79 @@
*out = str;
return Status::ok();
}
- Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override {
- *out = str;
+ Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+ *out = binder;
+ return Status::ok();
+ }
+ Status repeatBytes(const std::vector<uint8_t>& bytes, std::vector<uint8_t>* out) override {
+ *out = bytes;
return Status::ok();
}
};
-static sp<RpcSession> gSession = RpcSession::make();
+enum Transport {
+ KERNEL,
+ RPC,
+ RPC_TLS,
+};
-void BM_getRootObject(benchmark::State& state) {
- while (state.KeepRunning()) {
- CHECK(gSession->getRootObject() != nullptr);
+static const std::initializer_list<int64_t> kTransportList = {
+#ifdef __BIONIC__
+ Transport::KERNEL,
+#endif
+ Transport::RPC,
+ Transport::RPC_TLS,
+};
+
+std::unique_ptr<RpcTransportCtxFactory> makeFactoryTls() {
+ auto pkey = android::makeKeyPairForSelfSignedCert();
+ CHECK_NE(pkey.get(), nullptr);
+ auto cert = android::makeSelfSignedCert(pkey.get(), android::kCertValidSeconds);
+ CHECK_NE(cert.get(), nullptr);
+
+ auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(OK);
+ auto auth = std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
+ return RpcTransportCtxFactoryTls::make(verifier, std::move(auth));
+}
+
+static sp<RpcSession> gSession = RpcSession::make();
+// Certificate validation happens during handshake and does not affect the result of benchmarks.
+// Skip certificate validation to simplify the setup process.
+static sp<RpcSession> gSessionTls = RpcSession::make(makeFactoryTls());
+#ifdef __BIONIC__
+static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
+static sp<IBinder> gKernelBinder;
+#endif
+
+static sp<IBinder> getBinderForOptions(benchmark::State& state) {
+ Transport transport = static_cast<Transport>(state.range(0));
+ switch (transport) {
+#ifdef __BIONIC__
+ case KERNEL:
+ return gKernelBinder;
+#endif
+ case RPC:
+ return gSession->getRootObject();
+ case RPC_TLS:
+ return gSessionTls->getRootObject();
+ default:
+ LOG(FATAL) << "Unknown transport value: " << transport;
+ return nullptr;
}
}
-BENCHMARK(BM_getRootObject);
void BM_pingTransaction(benchmark::State& state) {
- sp<IBinder> binder = gSession->getRootObject();
- CHECK(binder != nullptr);
+ sp<IBinder> binder = getBinderForOptions(state);
while (state.KeepRunning()) {
CHECK_EQ(OK, binder->pingBinder());
}
}
-BENCHMARK(BM_pingTransaction);
+BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
-void BM_repeatString(benchmark::State& state) {
- sp<IBinder> binder = gSession->getRootObject();
- CHECK(binder != nullptr);
+void BM_repeatTwoPageString(benchmark::State& state) {
+ sp<IBinder> binder = getBinderForOptions(state);
+
sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
CHECK(iface != nullptr);
@@ -92,10 +163,30 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatString);
+BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList});
+
+void BM_throughputForTransportAndBytes(benchmark::State& state) {
+ sp<IBinder> binder = getBinderForOptions(state);
+ sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+ CHECK(iface != nullptr);
+
+ std::vector<uint8_t> bytes = std::vector<uint8_t>(state.range(1));
+ for (size_t i = 0; i < bytes.size(); i++) {
+ bytes[i] = i % 256;
+ }
+
+ while (state.KeepRunning()) {
+ std::vector<uint8_t> out;
+ Status ret = iface->repeatBytes(bytes, &out);
+ CHECK(ret.isOk()) << ret;
+ }
+}
+BENCHMARK(BM_throughputForTransportAndBytes)
+ ->ArgsProduct({kTransportList,
+ {64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}});
void BM_repeatBinder(benchmark::State& state) {
- sp<IBinder> binder = gSession->getRootObject();
+ sp<IBinder> binder = getBinderForOptions(state);
CHECK(binder != nullptr);
sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
CHECK(iface != nullptr);
@@ -109,29 +200,65 @@
CHECK(ret.isOk()) << ret;
}
}
-BENCHMARK(BM_repeatBinder);
+BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
+
+void forkRpcServer(const char* addr, const sp<RpcServer>& server) {
+ if (0 == fork()) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+ server->setRootObject(sp<MyBinderRpcBenchmark>::make());
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr));
+ server->join();
+ exit(1);
+ }
+}
+
+void setupClient(const sp<RpcSession>& session, const char* addr) {
+ status_t status;
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ status = session->setupUnixDomainClient(addr);
+ if (status == OK) break;
+ }
+ CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
+}
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::cerr << "Tests suffixes:" << std::endl;
+ std::cerr << "\t.../" << Transport::KERNEL << " is KERNEL" << std::endl;
+ std::cerr << "\t.../" << Transport::RPC << " is RPC" << std::endl;
+ std::cerr << "\t.../" << Transport::RPC_TLS << " is RPC with TLS" << std::endl;
- std::thread([addr]() {
- sp<RpcServer> server = RpcServer::make();
- server->setRootObject(sp<MyBinderRpcBenchmark>::make());
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- CHECK(server->setupUnixDomainServer(addr.c_str()));
- server->join();
- }).detach();
-
- for (size_t tries = 0; tries < 5; tries++) {
- usleep(10000);
- if (gSession->setupUnixDomainClient(addr.c_str())) goto success;
+#ifdef __BIONIC__
+ if (0 == fork()) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+ CHECK_EQ(OK,
+ defaultServiceManager()->addService(kKernelBinderInstance,
+ sp<MyBinderRpcBenchmark>::make()));
+ IPCThreadState::self()->joinThreadPool();
+ exit(1);
}
- LOG(FATAL) << "Could not connect.";
-success:
+
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+
+ gKernelBinder = defaultServiceManager()->waitForService(kKernelBinderInstance);
+ CHECK_NE(nullptr, gKernelBinder.get());
+#endif
+
+ std::string tmp = getenv("TMPDIR") ?: "/tmp";
+
+ std::string addr = tmp + "/binderRpcBenchmark";
+ (void)unlink(addr.c_str());
+ forkRpcServer(addr.c_str(), RpcServer::make(RpcTransportCtxFactoryRaw::make()));
+ setupClient(gSession, addr.c_str());
+
+ std::string tlsAddr = tmp + "/binderRpcTlsBenchmark";
+ (void)unlink(tlsAddr.c_str());
+ forkRpcServer(tlsAddr.c_str(), RpcServer::make(makeFactoryTls()));
+ setupClient(gSessionTls, tlsAddr.c_str());
::benchmark::RunSpecifiedBenchmarks();
return 0;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index a96deb5..c2639e7 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,34 +14,84 @@
* limitations under the License.
*/
+#include <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerInfo.h>
+#include <BnBinderRpcCallback.h>
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
#include <aidl/IBinderRpcTest.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/binder_auto_utils.h>
#include <android/binder_libbinder.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
#include <gtest/gtest.h>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <thread>
+#include <type_traits>
+#include <poll.h>
#include <sys/prctl.h>
#include <unistd.h>
-#include "../RpcState.h" // for debugging
-#include "../vm_sockets.h" // for VMADDR_*
+#include "../FdTrigger.h"
+#include "../RpcSocketAddress.h" // for testing preconnected clients
+#include "../RpcState.h" // for debugging
+#include "../vm_sockets.h" // for VMADDR_*
+
+using namespace std::chrono_literals;
+using namespace std::placeholders;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
namespace android {
+static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
+ RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+const char* kLocalInetAddress = "127.0.0.1";
+
+enum class RpcSecurity { RAW, TLS };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+ return {RpcSecurity::RAW, RpcSecurity::TLS};
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+ RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
+ std::unique_ptr<RpcAuth> auth = nullptr) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW:
+ return RpcTransportCtxFactoryRaw::make();
+ case RpcSecurity::TLS: {
+ if (verifier == nullptr) {
+ verifier = std::make_shared<RpcCertificateVerifierSimple>();
+ }
+ if (auth == nullptr) {
+ auth = std::make_unique<RpcAuthSelfSigned>();
+ }
+ return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+ }
+}
+
TEST(BinderRpcParcel, EntireParcelFormatted) {
Parcel p;
p.writeInt32(3);
@@ -49,19 +99,38 @@
EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}
-TEST(BinderRpc, SetExternalServer) {
+class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+public:
+ static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
+ return newFactory(info.param)->toCString();
+ }
+};
+
+TEST_P(BinderRpcSimple, SetExternalServerTest) {
base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
int sinkFd = sink.get();
- auto server = RpcServer::make();
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ auto server = RpcServer::make(newFactory(GetParam()));
ASSERT_FALSE(server->hasServer());
- ASSERT_TRUE(server->setupExternalServer(std::move(sink)));
+ ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
ASSERT_TRUE(server->hasServer());
base::unique_fd retrieved = server->releaseServer();
ASSERT_FALSE(server->hasServer());
ASSERT_EQ(sinkFd, retrieved.get());
}
+TEST(BinderRpc, CannotUseNextWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
+ EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
+}
+
+TEST(BinderRpc, CanUseExperimentalWireVersion) {
+ auto session = RpcSession::make();
+ EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
+}
+
using android::binder::Status;
#define EXPECT_OK(status) \
@@ -86,9 +155,26 @@
};
std::atomic<int32_t> MyBinderRpcSession::gNum;
+class MyBinderRpcCallback : public BnBinderRpcCallback {
+ Status sendCallback(const std::string& value) {
+ std::unique_lock _l(mMutex);
+ mValues.push_back(value);
+ _l.unlock();
+ mCv.notify_one();
+ return Status::ok();
+ }
+ Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
+
+public:
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ std::vector<std::string> mValues;
+};
+
class MyBinderRpcTest : public BnBinderRpcTest {
public:
wp<RpcServer> server;
+ int port = 0;
Status sendString(const std::string& str) override {
(void)str;
@@ -98,6 +184,10 @@
*strstr = str + str;
return Status::ok();
}
+ Status getClientPort(int* out) override {
+ *out = port;
+ return Status::ok();
+ }
Status countBinders(std::vector<int32_t>* out) override {
sp<RpcServer> spServer = server.promote();
if (spServer == nullptr) {
@@ -106,11 +196,6 @@
out->clear();
for (auto session : spServer->listSessions()) {
size_t count = session->state()->countBinders();
- if (count != 1) {
- // this is called when there is only one binder held remaining,
- // so to aid debugging
- session->state()->dump();
- }
out->push_back(count);
}
return Status::ok();
@@ -184,6 +269,33 @@
return sleepMs(ms);
}
+ Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+ const std::string& value) override {
+ if (callback == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+
+ if (delayed) {
+ std::thread([=]() {
+ ALOGE("Executing delayed callback: '%s'", value.c_str());
+ Status status = doCallback(callback, oneway, false, value);
+ ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
+ }).detach();
+ return Status::ok();
+ }
+
+ if (oneway) {
+ return callback->sendOnewayCallback(value);
+ }
+
+ return callback->sendCallback(value);
+ }
+
+ Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+ const std::string& value) override {
+ return doCallback(callback, oneway, delayed, value);
+ }
+
Status die(bool cleanup) override {
if (cleanup) {
exit(1);
@@ -191,50 +303,73 @@
_exit(1);
}
}
+
+ Status scheduleShutdown() override {
+ sp<RpcServer> strongServer = server.promote();
+ if (strongServer == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+ }
+ std::thread([=] {
+ LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
+ }).detach();
+ return Status::ok();
+ }
+
+ Status useKernelBinderCallingId() override {
+ // this is WRONG! It does not make sense when using RPC binder, and
+ // because it is SO wrong, and so much code calls this, it should abort!
+
+ (void)IPCThreadState::self()->getCallingPid();
+ return Status::ok();
+ }
};
sp<IBinder> MyBinderRpcTest::mHeldBinder;
-class Pipe {
-public:
- Pipe() { CHECK(android::base::Pipe(&mRead, &mWrite)); }
- Pipe(Pipe&&) = default;
- android::base::borrowed_fd readEnd() { return mRead; }
- android::base::borrowed_fd writeEnd() { return mWrite; }
-
-private:
- android::base::unique_fd mRead;
- android::base::unique_fd mWrite;
-};
-
class Process {
public:
Process(Process&&) = default;
- Process(const std::function<void(Pipe*)>& f) {
+ Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
+ android::base::borrowed_fd /* readEnd */)>& f) {
+ android::base::unique_fd childWriteEnd;
+ android::base::unique_fd childReadEnd;
+ CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
+ CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
if (0 == (mPid = fork())) {
// racey: assume parent doesn't crash before this is set
prctl(PR_SET_PDEATHSIG, SIGHUP);
- f(&mPipe);
+ f(childWriteEnd, childReadEnd);
+
+ exit(0);
}
}
~Process() {
if (mPid != 0) {
- kill(mPid, SIGKILL);
+ waitpid(mPid, nullptr, 0);
}
}
- Pipe* getPipe() { return &mPipe; }
+ android::base::borrowed_fd readEnd() { return mReadEnd; }
+ android::base::borrowed_fd writeEnd() { return mWriteEnd; }
private:
pid_t mPid = 0;
- Pipe mPipe;
+ android::base::unique_fd mReadEnd;
+ android::base::unique_fd mWriteEnd;
};
static std::string allocateSocketAddress() {
static size_t id = 0;
std::string temp = getenv("TMPDIR") ?: "/tmp";
- return temp + "/binderRpcTest_" + std::to_string(id++);
+ auto ret = temp + "/binderRpcTest_" + std::to_string(id++);
+ unlink(ret.c_str());
+ return ret;
};
+static unsigned int allocateVsockPort() {
+ static unsigned int vsockPort = 3456;
+ return vsockPort++;
+}
+
struct ProcessSession {
// reference to process hosting a socket server
Process host;
@@ -280,11 +415,14 @@
sp<IBinderRpcTest> rootIface;
// whether session should be invalidated by end of run
- bool expectInvalid = false;
+ bool expectAlreadyShutdown = false;
BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
~BinderRpcTestProcessSession() {
- if (!expectInvalid) {
+ EXPECT_NE(nullptr, rootIface);
+ if (rootIface == nullptr) return;
+
+ if (!expectAlreadyShutdown) {
std::vector<int32_t> remoteCounts;
// calling over any sessions counts across all sessions
EXPECT_OK(rootIface->countBinders(&remoteCounts));
@@ -292,6 +430,12 @@
for (auto remoteCount : remoteCounts) {
EXPECT_EQ(remoteCount, 1);
}
+
+ // even though it is on another thread, shutdown races with
+ // the transaction reply being written
+ if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+ }
}
rootIface = nullptr;
@@ -300,12 +444,15 @@
};
enum class SocketType {
+ PRECONNECTED,
UNIX,
VSOCK,
INET,
};
-static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
- switch (info.param) {
+static inline std::string PrintToString(SocketType socketType) {
+ switch (socketType) {
+ case SocketType::PRECONNECTED:
+ return "preconnected_uds";
case SocketType::UNIX:
return "unix_domain_socket";
case SocketType::VSOCK:
@@ -317,40 +464,100 @@
return "";
}
}
-class BinderRpc : public ::testing::TestWithParam<SocketType> {
+
+static base::unique_fd connectTo(const RpcSocketAddress& addr) {
+ base::unique_fd serverFd(
+ TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ int savedErrno = errno;
+ CHECK(serverFd.ok()) << "Could not create socket " << addr.toString() << ": "
+ << strerror(savedErrno);
+
+ if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+ int savedErrno = errno;
+ LOG(FATAL) << "Could not connect to socket " << addr.toString() << ": "
+ << strerror(savedErrno);
+ }
+ return serverFd;
+}
+
+class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
public:
+ struct Options {
+ size_t numThreads = 1;
+ size_t numSessions = 1;
+ size_t numIncomingConnections = 0;
+ size_t numOutgoingConnections = SIZE_MAX;
+ };
+
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [type, security] = info.param;
+ return PrintToString(type) + "_" + newFactory(security)->toCString();
+ }
+
+ static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+ uint64_t length = str.length();
+ CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+ CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+ }
+
+ static inline std::string readString(android::base::borrowed_fd fd) {
+ uint64_t length;
+ CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+ std::string ret(length, '\0');
+ CHECK(android::base::ReadFully(fd, ret.data(), length));
+ return ret;
+ }
+
+ static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+ Parcel parcel;
+ CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+ writeString(fd,
+ std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+ }
+
+ template <typename T>
+ static inline T readFromFd(android::base::borrowed_fd fd) {
+ std::string data = readString(fd);
+ Parcel parcel;
+ CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+ T object;
+ CHECK_EQ(OK, object.readFromParcel(&parcel));
+ return object;
+ }
+
// This creates a new process serving an interface on a certain number of
// threads.
ProcessSession createRpcTestSocketServerProcess(
- size_t numThreads, size_t numSessions,
- const std::function<void(const sp<RpcServer>&)>& configure) {
- CHECK_GE(numSessions, 1) << "Must have at least one session to a server";
+ const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
+ CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
- SocketType socketType = GetParam();
+ SocketType socketType = std::get<0>(GetParam());
+ RpcSecurity rpcSecurity = std::get<1>(GetParam());
+ unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
- unlink(addr.c_str());
- static unsigned int vsockPort = 3456;
- vsockPort++;
auto ret = ProcessSession{
- .host = Process([&](Pipe* pipe) {
- sp<RpcServer> server = RpcServer::make();
+ .host = Process([&](android::base::borrowed_fd writeEnd,
+ android::base::borrowed_fd readEnd) {
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- server->setMaxThreads(numThreads);
+ server->setMaxThreads(options.numThreads);
unsigned int outPort = 0;
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ [[fallthrough]];
case SocketType::UNIX:
- CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
break;
case SocketType::VSOCK:
- CHECK(server->setupVsockServer(vsockPort));
+ CHECK_EQ(OK, server->setupVsockServer(vsockPort));
break;
case SocketType::INET: {
- CHECK(server->setupInetServer(0, &outPort));
+ CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
CHECK_NE(0, outPort);
break;
}
@@ -358,53 +565,123 @@
LOG_ALWAYS_FATAL("Unknown socket type");
}
- CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort, sizeof(outPort)));
+ BinderRpcTestServerInfo serverInfo;
+ serverInfo.port = static_cast<int64_t>(outPort);
+ serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+ writeToFd(writeEnd, serverInfo);
+ auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ for (const auto& clientCert : clientInfo.certs) {
+ CHECK_EQ(OK,
+ certVerifier
+ ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ clientCert.data));
+ }
+ }
configure(server);
server->join();
+
+ // Another thread calls shutdown. Wait for it to complete.
+ (void)server->shutdown();
}),
};
- // always read socket, so that we have waited for the server to start
- unsigned int outPort = 0;
- CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &outPort, sizeof(outPort)));
- if (socketType == SocketType::INET) {
- CHECK_NE(0, outPort);
+ std::vector<sp<RpcSession>> sessions;
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ for (size_t i = 0; i < options.numSessions; i++) {
+ sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
}
- for (size_t i = 0; i < numSessions; i++) {
- sp<RpcSession> session = RpcSession::make();
+ auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
+ BinderRpcTestClientInfo clientInfo;
+ for (const auto& session : sessions) {
+ auto& parcelableCert = clientInfo.certs.emplace_back();
+ parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+ }
+ writeToFd(ret.host.writeEnd(), clientInfo);
+
+ CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
+ if (socketType == SocketType::INET) {
+ CHECK_NE(0, serverInfo.port);
+ }
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ const auto& serverCert = serverInfo.cert.data;
+ CHECK_EQ(OK,
+ certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ serverCert));
+ }
+
+ status_t status;
+
+ for (const auto& session : sessions) {
+ session->setMaxIncomingThreads(options.numIncomingConnections);
+ session->setMaxOutgoingThreads(options.numOutgoingConnections);
+
switch (socketType) {
+ case SocketType::PRECONNECTED:
+ status = session->setupPreconnectedClient({}, [=]() {
+ return connectTo(UnixSocketAddress(addr.c_str()));
+ });
+ break;
case SocketType::UNIX:
- if (session->setupUnixDomainClient(addr.c_str())) goto success;
+ status = session->setupUnixDomainClient(addr.c_str());
break;
case SocketType::VSOCK:
- if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+ status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
break;
case SocketType::INET:
- if (session->setupInetClient("127.0.0.1", outPort)) goto success;
+ status = session->setupInetClient("127.0.0.1", serverInfo.port);
break;
default:
LOG_ALWAYS_FATAL("Unknown socket type");
}
- LOG_ALWAYS_FATAL("Could not connect");
- success:
+ CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
ret.sessions.push_back({session, session->getRootObject()});
}
return ret;
}
- BinderRpcTestProcessSession createRpcTestSocketServerProcess(size_t numThreads,
- size_t numSessions = 1) {
+ BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
BinderRpcTestProcessSession ret{
- .proc = createRpcTestSocketServerProcess(numThreads, numSessions,
- [&](const sp<RpcServer>& server) {
- sp<MyBinderRpcTest> service =
- new MyBinderRpcTest;
- server->setRootObject(service);
- service->server = server;
- }),
+ .proc = createRpcTestSocketServerProcess(
+ options,
+ [&](const sp<RpcServer>& server) {
+ server->setPerSessionRootObject([&](const sockaddr* addr,
+ socklen_t len) {
+ sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
+ switch (addr->sa_family) {
+ case AF_UNIX:
+ // nothing to save
+ break;
+ case AF_VSOCK:
+ CHECK_EQ(len, sizeof(sockaddr_vm));
+ service->port = reinterpret_cast<const sockaddr_vm*>(addr)
+ ->svm_port;
+ break;
+ case AF_INET:
+ CHECK_EQ(len, sizeof(sockaddr_in));
+ service->port =
+ ntohs(reinterpret_cast<const sockaddr_in*>(addr)
+ ->sin_port);
+ break;
+ case AF_INET6:
+ CHECK_EQ(len, sizeof(sockaddr_in));
+ service->port =
+ ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
+ ->sin6_port);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized address family %d",
+ addr->sa_family);
+ }
+ service->server = server;
+ return service;
+ });
+ }),
};
ret.rootBinder = ret.proc.sessions.at(0).root;
@@ -412,59 +689,82 @@
return ret;
}
+
+ void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+ size_t sleepMs = 500);
};
-TEST_P(BinderRpc, RootObjectIsNull) {
- auto proc = createRpcTestSocketServerProcess(1, 1, [](const sp<RpcServer>& server) {
- // this is the default, but to be explicit
- server->setRootObject(nullptr);
- });
-
- EXPECT_EQ(nullptr, proc.sessions.at(0).root);
-}
-
TEST_P(BinderRpc, Ping) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
ASSERT_NE(proc.rootBinder, nullptr);
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
}
TEST_P(BinderRpc, GetInterfaceDescriptor) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
ASSERT_NE(proc.rootBinder, nullptr);
EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
}
TEST_P(BinderRpc, MultipleSessions) {
- auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 5 /*sessions*/);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
for (auto session : proc.proc.sessions) {
ASSERT_NE(nullptr, session.root);
EXPECT_EQ(OK, session.root->pingBinder());
}
}
+TEST_P(BinderRpc, SeparateRootObject) {
+ SocketType type = std::get<0>(GetParam());
+ if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
+ // we can't get port numbers for unix sockets
+ return;
+ }
+
+ auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
+
+ int port1 = 0;
+ EXPECT_OK(proc.rootIface->getClientPort(&port1));
+
+ sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+ int port2;
+ EXPECT_OK(rootIface2->getClientPort(&port2));
+
+ // we should have a different IBinderRpcTest object created for each
+ // session, because we use setPerSessionRootObject
+ EXPECT_NE(port1, port2);
+}
+
TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
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);
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
+
+ Parcel pRaw;
Parcel p1;
- p1.markForBinder(proc.rootBinder);
+ p1.markForBinder(proc1.rootBinder);
p1.writeInt32(3);
+ EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, p1.dataSize()));
+ EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
Parcel p2;
+ p2.markForBinder(proc2.rootBinder);
+ p2.writeInt32(7);
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);
+ auto proc = createRpcTestSocketServerProcess({});
Parcel data;
data.markForBinder(proc.rootBinder);
Parcel reply;
@@ -472,19 +772,19 @@
}
TEST_P(BinderRpc, SendSomethingOneway) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
EXPECT_OK(proc.rootIface->sendString("asdf"));
}
TEST_P(BinderRpc, SendAndGetResultBack) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
std::string doubled;
EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
EXPECT_EQ("cool cool ", doubled);
}
TEST_P(BinderRpc, SendAndGetResultBackBig) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
std::string single = std::string(1024, 'a');
std::string doubled;
EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
@@ -492,7 +792,7 @@
}
TEST_P(BinderRpc, CallMeBack) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
int32_t pingResult;
EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
@@ -502,7 +802,7 @@
}
TEST_P(BinderRpc, RepeatBinder) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> inBinder = new MyBinderRpcSession("foo");
sp<IBinder> outBinder;
@@ -524,7 +824,7 @@
}
TEST_P(BinderRpc, RepeatTheirBinder) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinderRpcSession> session;
EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
@@ -548,7 +848,7 @@
}
TEST_P(BinderRpc, RepeatBinderNull) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> outBinder;
EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
@@ -556,7 +856,7 @@
}
TEST_P(BinderRpc, HoldBinder) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
IBinder* ptr = nullptr;
{
@@ -582,8 +882,8 @@
// aren't supported.
TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
- auto proc1 = createRpcTestSocketServerProcess(1);
- auto proc2 = createRpcTestSocketServerProcess(1);
+ auto proc1 = createRpcTestSocketServerProcess({});
+ auto proc2 = createRpcTestSocketServerProcess({});
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
@@ -591,7 +891,7 @@
}
TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
- auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 2 /*sessions*/);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
@@ -600,7 +900,7 @@
}
TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
sp<IBinder> outBinder;
@@ -609,7 +909,7 @@
}
TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
// for historical reasons, IServiceManager interface only returns the
// exception code
@@ -620,7 +920,7 @@
// END TESTS FOR LIMITATIONS OF SOCKET BINDER
TEST_P(BinderRpc, RepeatRootObject) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> outBinder;
EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
@@ -628,7 +928,7 @@
}
TEST_P(BinderRpc, NestedTransactions) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
auto nastyNester = sp<MyBinderRpcTest>::make();
EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
@@ -639,7 +939,7 @@
}
TEST_P(BinderRpc, SameBinderEquality) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> a;
EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
@@ -651,7 +951,7 @@
}
TEST_P(BinderRpc, SameBinderEqualityWeak) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinder> a;
EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
@@ -683,7 +983,7 @@
} while (false)
TEST_P(BinderRpc, SingleSession) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
sp<IBinderRpcSession> session;
EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
@@ -697,7 +997,7 @@
}
TEST_P(BinderRpc, ManySessions) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
std::vector<sp<IBinderRpcSession>> sessions;
@@ -733,7 +1033,7 @@
TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
constexpr size_t kNumThreads = 10;
- auto proc = createRpcTestSocketServerProcess(kNumThreads);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
EXPECT_OK(proc.rootIface->lock());
@@ -762,28 +1062,39 @@
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);
-
+void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+ size_t sleepMs) {
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 (size_t i = 0; i < numCalls; i++) {
+ ts.push_back(std::thread([&] { iface->sleepMs(sleepMs); }));
}
for (auto& t : ts) t.join();
size_t epochMsAfter = epochMillis();
- EXPECT_GE(epochMsAfter, epochMsBefore + 2 * kSleepMs);
+ EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
// Potential flake, but make sure calls are handled in parallel.
- EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
+ EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
+}
+
+TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+ constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumCalls = kNumThreads + 3;
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
+}
+
+TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
+ constexpr size_t kNumThreads = 20;
+ constexpr size_t kNumOutgoingConnections = 10;
+ constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
+ auto proc = createRpcTestSocketServerProcess(
+ {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
}
TEST_P(BinderRpc, ThreadingStressTest) {
@@ -791,7 +1102,7 @@
constexpr size_t kNumServerThreads = 10;
constexpr size_t kNumCalls = 100;
- auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
std::vector<std::thread> threads;
for (size_t i = 0; i < kNumClientThreads; i++) {
@@ -807,12 +1118,20 @@
for (auto& t : threads) t.join();
}
+static void saturateThreadPool(size_t threadCount, const sp<IBinderRpcTest>& iface) {
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < threadCount; i++) {
+ threads.push_back(std::thread([&] { EXPECT_OK(iface->sleepMs(500)); }));
+ }
+ 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;
+ constexpr size_t kNumCalls = 1000;
- auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
std::vector<std::thread> threads;
for (size_t i = 0; i < kNumClientThreads; i++) {
@@ -820,21 +1139,19 @@
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();
+
+ saturateThreadPool(kNumServerThreads, proc.rootIface);
}
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);
+ auto proc = createRpcTestSocketServerProcess({});
size_t epochMsBefore = epochMillis();
@@ -850,27 +1167,126 @@
constexpr size_t kSleepMs = 50;
// make sure calls to the same object happen on the same thread
- auto proc = createRpcTestSocketServerProcess(1 + kNumExtraServerThreads);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 1 + kNumExtraServerThreads});
EXPECT_OK(proc.rootIface->lock());
- for (size_t i = 0; i < kNumSleeps; i++) {
- // these should be processed serially
+ size_t epochMsBefore = epochMillis();
+
+ // all these *Async commands should be queued on the server sequentially,
+ // even though there are multiple threads.
+ for (size_t i = 0; i + 1 < kNumSleeps; i++) {
proc.rootIface->sleepMsAsync(kSleepMs);
}
- // should also be processesed serially
EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
- size_t epochMsBefore = epochMillis();
+ // this can only return once the final async call has unlocked
EXPECT_OK(proc.rootIface->lockUnlock());
+
size_t epochMsAfter = epochMillis();
EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+
+ saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
+}
+
+TEST_P(BinderRpc, OnewayCallExhaustion) {
+ constexpr size_t kNumClients = 2;
+ constexpr size_t kTooLongMs = 1000;
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumClients, .numSessions = 2});
+
+ // Build up oneway calls on the second session to make sure it terminates
+ // and shuts down. The first session should be unaffected (proc destructor
+ // checks the first session).
+ auto iface = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < kNumClients; i++) {
+ // one of these threads will get stuck queueing a transaction once the
+ // socket fills up, the other will be able to fill up transactions on
+ // this object
+ threads.push_back(std::thread([&] {
+ while (iface->sleepMsAsync(kTooLongMs).isOk()) {
+ }
+ }));
+ }
+ for (auto& t : threads) t.join();
+
+ Status status = iface->sleepMsAsync(kTooLongMs);
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+
+ // now that it has died, wait for the remote session to shutdown
+ std::vector<int32_t> remoteCounts;
+ do {
+ EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
+ } while (remoteCounts.size() == kNumClients);
+
+ // the second session should be shutdown in the other process by the time we
+ // are able to join above (it'll only be hung up once it finishes processing
+ // any pending commands). We need to erase this session from the record
+ // here, so that the destructor for our session won't check that this
+ // session is valid, but we still want it to test the other session.
+ proc.proc.sessions.erase(proc.proc.sessions.begin() + 1);
+}
+
+TEST_P(BinderRpc, Callbacks) {
+ const static std::string kTestString = "good afternoon!";
+
+ for (bool callIsOneway : {true, false}) {
+ for (bool callbackIsOneway : {true, false}) {
+ for (bool delayed : {true, false}) {
+ auto proc = createRpcTestSocketServerProcess(
+ {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+ auto cb = sp<MyBinderRpcCallback>::make();
+
+ if (callIsOneway) {
+ EXPECT_OK(proc.rootIface->doCallbackAsync(cb, callbackIsOneway, delayed,
+ kTestString));
+ } else {
+ EXPECT_OK(
+ proc.rootIface->doCallback(cb, callbackIsOneway, delayed, kTestString));
+ }
+
+ using std::literals::chrono_literals::operator""s;
+ std::unique_lock<std::mutex> _l(cb->mMutex);
+ cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
+
+ EXPECT_EQ(cb->mValues.size(), 1)
+ << "callIsOneway: " << callIsOneway
+ << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+ if (cb->mValues.empty()) continue;
+ EXPECT_EQ(cb->mValues.at(0), kTestString)
+ << "callIsOneway: " << callIsOneway
+ << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed;
+
+ // since we are severing the connection, we need to go ahead and
+ // tell the server to shutdown and exit so that waitpid won't hang
+ if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+ EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+ }
+
+ // since this session has an incoming connection w/ a threadpool, we
+ // need to manually shut it down
+ EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+
+ proc.expectAlreadyShutdown = true;
+ }
+ }
+ }
+}
+
+TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto cb = sp<MyBinderRpcCallback>::make();
+
+ Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
+ EXPECT_EQ(WOULD_BLOCK, status.transactionError());
}
TEST_P(BinderRpc, Die) {
for (bool doDeathCleanup : {true, false}) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
// make sure there is some state during crash
// 1. we hold their binder
@@ -883,12 +1299,34 @@
EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
<< "Do death cleanup: " << doDeathCleanup;
- proc.expectInvalid = true;
+ proc.expectAlreadyShutdown = true;
}
}
+TEST_P(BinderRpc, UseKernelBinderCallingId) {
+ bool okToFork = ProcessState::selfOrNull() == nullptr;
+
+ auto proc = createRpcTestSocketServerProcess({});
+
+ // If this process has used ProcessState already, then the forked process
+ // cannot use it at all. If this process hasn't used it (depending on the
+ // order tests are run), then the forked process can use it, and we'll only
+ // catch the invalid usage the second time. Such is the burden of global
+ // state!
+ if (okToFork) {
+ // we can't allocate IPCThreadState so actually the first time should
+ // succeed :(
+ EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+ }
+
+ // second time! we catch the error :)
+ EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
+
+ proc.expectAlreadyShutdown = true;
+}
+
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
ASSERT_NE(binder, nullptr);
@@ -897,7 +1335,7 @@
}
TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
- auto proc = createRpcTestSocketServerProcess(1);
+ auto proc = createRpcTestSocketServerProcess({});
ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
ASSERT_NE(binder, nullptr);
@@ -925,24 +1363,62 @@
ssize_t beforeFds = countFds();
ASSERT_GE(beforeFds, 0);
{
- auto proc = createRpcTestSocketServerProcess(10);
+ auto proc = createRpcTestSocketServerProcess({.numThreads = 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,
-// TODO(b/185269356): working on host
-#ifdef __BIONIC__
- SocketType::VSOCK,
-#endif
- SocketType::INET,
- }),
- PrintSocketType);
+TEST_P(BinderRpc, AidlDelegatorTest) {
+ auto proc = createRpcTestSocketServerProcess({});
+ auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+ ASSERT_NE(nullptr, myDelegator);
-class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool>> {};
+ std::string doubled;
+ EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+ EXPECT_EQ("cool cool ", doubled);
+}
+
+static bool testSupportVsockLoopback() {
+ // We don't need to enable TLS to know if vsock is supported.
+ unsigned int vsockPort = allocateVsockPort();
+ sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
+ if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
+ if (status == -EAFNOSUPPORT) {
+ return false;
+ }
+ LOG_ALWAYS_FATAL("Could not setup vsock server: %s", statusToString(status).c_str());
+ }
+ server->start();
+
+ sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+ while (!server->shutdown()) usleep(10000);
+ ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
+ return status == OK;
+}
+
+static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
+ std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+
+ if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
+
+ static bool hasVsockLoopback = testSupportVsockLoopback();
+
+ if (hasVsockLoopback) {
+ ret.push_back(SocketType::VSOCK);
+ }
+
+ return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+ ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+ ::testing::ValuesIn(RpcSecurityValues())),
+ BinderRpc::PrintParamInfo);
+
+class BinderRpcServerRootObject
+ : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
TEST_P(BinderRpcServerRootObject, WeakRootObject) {
using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
@@ -950,8 +1426,8 @@
return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
};
- auto server = RpcServer::make();
- auto [isStrong1, isStrong2] = GetParam();
+ auto [isStrong1, isStrong2, rpcSecurity] = GetParam();
+ auto server = RpcServer::make(newFactory(rpcSecurity));
auto binder1 = sp<BBinder>::make();
IBinder* binderRaw1 = binder1.get();
setRootObject(isStrong1)(server.get(), binder1);
@@ -968,12 +1444,583 @@
}
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
- ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+ ::testing::Combine(::testing::Bool(), ::testing::Bool(),
+ ::testing::ValuesIn(RpcSecurityValues())));
+
+class OneOffSignal {
+public:
+ // If notify() was previously called, or is called within |duration|, return true; else false.
+ template <typename R, typename P>
+ bool wait(std::chrono::duration<R, P> duration) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ return mCv.wait_for(lock, duration, [this] { return mValue; });
+ }
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mValue = true;
+ lock.unlock();
+ mCv.notify_all();
+ }
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mValue = false;
+};
+
+TEST_P(BinderRpcSimple, Shutdown) {
+ auto addr = allocateSocketAddress();
+ auto server = RpcServer::make(newFactory(GetParam()));
+ ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+ auto joinEnds = std::make_shared<OneOffSignal>();
+
+ // If things are broken and the thread never stops, don't block other tests. Because the thread
+ // may run after the test finishes, it must not access the stack memory of the test. Hence,
+ // shared pointers are passed.
+ std::thread([server, joinEnds] {
+ server->join();
+ joinEnds->notify();
+ }).detach();
+
+ bool shutdown = false;
+ for (int i = 0; i < 10 && !shutdown; i++) {
+ usleep(300 * 1000); // 300ms; total 3s
+ if (server->shutdown()) shutdown = true;
+ }
+ ASSERT_TRUE(shutdown) << "server->shutdown() never returns true";
+
+ ASSERT_TRUE(joinEnds->wait(2s))
+ << "After server->shutdown() returns true, join() did not stop after 2s";
+}
+
+TEST(BinderRpc, Java) {
+#if !defined(__ANDROID__)
+ GTEST_SKIP() << "This test is only run on Android. Though it can technically run on host on"
+ "createRpcDelegateServiceManager() with a device attached, such test belongs "
+ "to binderHostDeviceTest. Hence, just disable this test on host.";
+#endif // !__ANDROID__
+ sp<IServiceManager> sm = defaultServiceManager();
+ ASSERT_NE(nullptr, sm);
+ // Any Java service with non-empty getInterfaceDescriptor() would do.
+ // Let's pick batteryproperties.
+ auto binder = sm->checkService(String16("batteryproperties"));
+ ASSERT_NE(nullptr, binder);
+ auto descriptor = binder->getInterfaceDescriptor();
+ ASSERT_GE(descriptor.size(), 0);
+ ASSERT_EQ(OK, binder->pingBinder());
+
+ auto rpcServer = RpcServer::make();
+ unsigned int port;
+ ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
+ auto socket = rpcServer->releaseServer();
+
+ auto keepAlive = sp<BBinder>::make();
+ auto setRpcClientDebugStatus = binder->setRpcClientDebug(std::move(socket), keepAlive);
+
+ if (!android::base::GetBoolProperty("ro.debuggable", false) ||
+ android::base::GetProperty("ro.build.type", "") == "user") {
+ ASSERT_EQ(INVALID_OPERATION, setRpcClientDebugStatus)
+ << "setRpcClientDebug should return INVALID_OPERATION on non-debuggable or user "
+ "builds, but get "
+ << statusToString(setRpcClientDebugStatus);
+ GTEST_SKIP();
+ }
+
+ ASSERT_EQ(OK, setRpcClientDebugStatus);
+
+ auto rpcSession = RpcSession::make();
+ ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
+ auto rpcBinder = rpcSession->getRootObject();
+ ASSERT_NE(nullptr, rpcBinder);
+
+ ASSERT_EQ(OK, rpcBinder->pingBinder());
+
+ ASSERT_EQ(descriptor, rpcBinder->getInterfaceDescriptor())
+ << "getInterfaceDescriptor should not crash system_server";
+ ASSERT_EQ(OK, rpcBinder->pingBinder());
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
+ BinderRpcSimple::PrintTestParam);
+
+class RpcTransportTestUtils {
+public:
+ using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
+ using ConnectToServer = std::function<base::unique_fd()>;
+
+ // A server that handles client socket connections.
+ class Server {
+ public:
+ explicit Server() {}
+ Server(Server&&) = default;
+ ~Server() { shutdownAndWait(); }
+ [[nodiscard]] AssertionResult setUp(
+ const Param& param,
+ std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
+ auto [socketType, rpcSecurity, certificateFormat] = param;
+ auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+ switch (socketType) {
+ case SocketType::PRECONNECTED: {
+ return AssertionFailure() << "Not supported by this test";
+ } break;
+ case SocketType::UNIX: {
+ auto addr = allocateSocketAddress();
+ auto status = rpcServer->setupUnixDomainServer(addr.c_str());
+ if (status != OK) {
+ return AssertionFailure()
+ << "setupUnixDomainServer: " << statusToString(status);
+ }
+ mConnectToServer = [addr] {
+ return connectTo(UnixSocketAddress(addr.c_str()));
+ };
+ } break;
+ case SocketType::VSOCK: {
+ auto port = allocateVsockPort();
+ auto status = rpcServer->setupVsockServer(port);
+ if (status != OK) {
+ return AssertionFailure() << "setupVsockServer: " << statusToString(status);
+ }
+ mConnectToServer = [port] {
+ return connectTo(VsockSocketAddress(VMADDR_CID_LOCAL, port));
+ };
+ } break;
+ case SocketType::INET: {
+ unsigned int port;
+ auto status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port);
+ if (status != OK) {
+ return AssertionFailure() << "setupInetServer: " << statusToString(status);
+ }
+ mConnectToServer = [port] {
+ const char* addr = kLocalInetAddress;
+ auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
+ if (aiStart == nullptr) return base::unique_fd{};
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ auto fd = connectTo(
+ InetSocketAddress(ai->ai_addr, ai->ai_addrlen, addr, port));
+ if (fd.ok()) return fd;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be connected",
+ addr, port);
+ return base::unique_fd{};
+ };
+ }
+ }
+ mFd = rpcServer->releaseServer();
+ if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
+ mCtx = newFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
+ if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
+ mSetup = true;
+ return AssertionSuccess();
+ }
+ RpcTransportCtx* getCtx() const { return mCtx.get(); }
+ std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+ return mCertVerifier;
+ }
+ ConnectToServer getConnectToServerFn() { return mConnectToServer; }
+ void start() {
+ LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+ mThread = std::make_unique<std::thread>(&Server::run, this);
+ }
+ void run() {
+ LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+
+ std::vector<std::thread> threads;
+ while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
+ base::unique_fd acceptedFd(
+ TEMP_FAILURE_RETRY(accept4(mFd.get(), nullptr, nullptr /*length*/,
+ SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
+ }
+
+ for (auto& thread : threads) thread.join();
+ }
+ void handleOne(android::base::unique_fd acceptedFd) {
+ ASSERT_TRUE(acceptedFd.ok());
+ auto serverTransport = mCtx->newTransport(std::move(acceptedFd), mFdTrigger.get());
+ if (serverTransport == nullptr) return; // handshake failed
+ ASSERT_TRUE(mPostConnect(serverTransport.get(), mFdTrigger.get()));
+ }
+ void shutdownAndWait() {
+ shutdown();
+ join();
+ }
+ void shutdown() { mFdTrigger->trigger(); }
+
+ void setPostConnect(
+ std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> fn) {
+ mPostConnect = std::move(fn);
+ }
+
+ private:
+ std::unique_ptr<std::thread> mThread;
+ ConnectToServer mConnectToServer;
+ std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+ base::unique_fd mFd;
+ std::unique_ptr<RpcTransportCtx> mCtx;
+ std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+ std::make_shared<RpcCertificateVerifierSimple>();
+ bool mSetup = false;
+ // The function invoked after connection and handshake. By default, it is
+ // |defaultPostConnect| that sends |kMessage| to the client.
+ std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> mPostConnect =
+ Server::defaultPostConnect;
+
+ void join() {
+ if (mThread != nullptr) {
+ mThread->join();
+ mThread = nullptr;
+ }
+ }
+
+ static AssertionResult defaultPostConnect(RpcTransport* serverTransport,
+ FdTrigger* fdTrigger) {
+ std::string message(kMessage);
+ iovec messageIov{message.data(), message.size()};
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
+ if (status != OK) return AssertionFailure() << statusToString(status);
+ return AssertionSuccess();
+ }
+ };
+
+ class Client {
+ public:
+ explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
+ Client(Client&&) = default;
+ [[nodiscard]] AssertionResult setUp(const Param& param) {
+ auto [socketType, rpcSecurity, certificateFormat] = param;
+ mFdTrigger = FdTrigger::make();
+ mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
+ if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
+ return AssertionSuccess();
+ }
+ RpcTransportCtx* getCtx() const { return mCtx.get(); }
+ std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+ return mCertVerifier;
+ }
+ // connect() and do handshake
+ bool setUpTransport() {
+ mFd = mConnectToServer();
+ if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
+ mClientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
+ return mClientTransport != nullptr;
+ }
+ AssertionResult readMessage(const std::string& expectedMessage = kMessage) {
+ LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
+ std::string readMessage(expectedMessage.size(), '\0');
+ iovec readMessageIov{readMessage.data(), readMessage.size()};
+ status_t readStatus = mClientTransport->interruptableReadFully(mFdTrigger.get(),
+ &readMessageIov, 1, {});
+ if (readStatus != OK) {
+ return AssertionFailure() << statusToString(readStatus);
+ }
+ if (readMessage != expectedMessage) {
+ return AssertionFailure()
+ << "Expected " << expectedMessage << ", actual " << readMessage;
+ }
+ return AssertionSuccess();
+ }
+ void run(bool handshakeOk = true, bool readOk = true) {
+ if (!setUpTransport()) {
+ ASSERT_FALSE(handshakeOk) << "newTransport returns nullptr, but it shouldn't";
+ return;
+ }
+ ASSERT_TRUE(handshakeOk) << "newTransport does not return nullptr, but it should";
+ ASSERT_EQ(readOk, readMessage());
+ }
+
+ private:
+ ConnectToServer mConnectToServer;
+ base::unique_fd mFd;
+ std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+ std::unique_ptr<RpcTransportCtx> mCtx;
+ std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+ std::make_shared<RpcCertificateVerifierSimple>();
+ std::unique_ptr<RpcTransport> mClientTransport;
+ };
+
+ // Make A trust B.
+ template <typename A, typename B>
+ static status_t trust(RpcSecurity rpcSecurity,
+ std::optional<RpcCertificateFormat> certificateFormat, const A& a,
+ const B& b) {
+ if (rpcSecurity != RpcSecurity::TLS) return OK;
+ LOG_ALWAYS_FATAL_IF(!certificateFormat.has_value());
+ auto bCert = b->getCtx()->getCertificate(*certificateFormat);
+ return a->getCertVerifier()->addTrustedPeerCertificate(*certificateFormat, bCert);
+ }
+
+ static constexpr const char* kMessage = "hello";
+};
+
+class RpcTransportTest : public testing::TestWithParam<RpcTransportTestUtils::Param> {
+public:
+ using Server = RpcTransportTestUtils::Server;
+ using Client = RpcTransportTestUtils::Client;
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [socketType, rpcSecurity, certificateFormat] = info.param;
+ auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
+ if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+ return ret;
+ }
+ static std::vector<ParamType> getRpcTranportTestParams() {
+ std::vector<ParamType> ret;
+ for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+ for (auto rpcSecurity : RpcSecurityValues()) {
+ switch (rpcSecurity) {
+ case RpcSecurity::RAW: {
+ ret.emplace_back(socketType, rpcSecurity, std::nullopt);
+ } break;
+ case RpcSecurity::TLS: {
+ ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
+ ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
+ } break;
+ }
+ }
+ }
+ return ret;
+ }
+ template <typename A, typename B>
+ status_t trust(const A& a, const B& b) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
+ }
+};
+
+TEST_P(RpcTransportTest, GoodCertificate) {
+ auto server = std::make_unique<Server>();
+ ASSERT_TRUE(server->setUp(GetParam()));
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+
+ server->start();
+ client.run();
+}
+
+TEST_P(RpcTransportTest, MultipleClients) {
+ auto server = std::make_unique<Server>();
+ ASSERT_TRUE(server->setUp(GetParam()));
+
+ std::vector<Client> clients;
+ for (int i = 0; i < 2; i++) {
+ auto& client = clients.emplace_back(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+ }
+
+ server->start();
+ for (auto& client : clients) client.run();
+}
+
+TEST_P(RpcTransportTest, UntrustedServer) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+
+ auto untrustedServer = std::make_unique<Server>();
+ ASSERT_TRUE(untrustedServer->setUp(GetParam()));
+
+ Client client(untrustedServer->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+
+ ASSERT_EQ(OK, trust(untrustedServer, &client));
+
+ untrustedServer->start();
+
+ // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+ // the client can't verify the server's identity.
+ bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(handshakeOk);
+}
+TEST_P(RpcTransportTest, MaliciousServer) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto validServer = std::make_unique<Server>();
+ ASSERT_TRUE(validServer->setUp(GetParam()));
+
+ auto maliciousServer = std::make_unique<Server>();
+ ASSERT_TRUE(maliciousServer->setUp(GetParam()));
+
+ Client client(maliciousServer->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+
+ ASSERT_EQ(OK, trust(&client, validServer));
+ ASSERT_EQ(OK, trust(validServer, &client));
+ ASSERT_EQ(OK, trust(maliciousServer, &client));
+
+ maliciousServer->start();
+
+ // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+ // the client can't verify the server's identity.
+ bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(handshakeOk);
+}
+
+TEST_P(RpcTransportTest, UntrustedClient) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto server = std::make_unique<Server>();
+ ASSERT_TRUE(server->setUp(GetParam()));
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+
+ ASSERT_EQ(OK, trust(&client, server));
+
+ server->start();
+
+ // For TLS, Client should be able to verify server's identity, so client should see
+ // do_handshake() successfully executed. However, server shouldn't be able to verify client's
+ // identity and should drop the connection, so client shouldn't be able to read anything.
+ bool readOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, MaliciousClient) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto server = std::make_unique<Server>();
+ ASSERT_TRUE(server->setUp(GetParam()));
+
+ Client validClient(server->getConnectToServerFn());
+ ASSERT_TRUE(validClient.setUp(GetParam()));
+ Client maliciousClient(server->getConnectToServerFn());
+ ASSERT_TRUE(maliciousClient.setUp(GetParam()));
+
+ ASSERT_EQ(OK, trust(&validClient, server));
+ ASSERT_EQ(OK, trust(&maliciousClient, server));
+
+ server->start();
+
+ // See UntrustedClient.
+ bool readOk = rpcSecurity != RpcSecurity::TLS;
+ maliciousClient.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, Trigger) {
+ std::string msg2 = ", world!";
+ std::mutex writeMutex;
+ std::condition_variable writeCv;
+ bool shouldContinueWriting = false;
+ auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
+ std::string message(RpcTransportTestUtils::kMessage);
+ iovec messageIov{message.data(), message.size()};
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
+ if (status != OK) return AssertionFailure() << statusToString(status);
+
+ {
+ std::unique_lock<std::mutex> lock(writeMutex);
+ if (!writeCv.wait_for(lock, 3s, [&] { return shouldContinueWriting; })) {
+ return AssertionFailure() << "write barrier not cleared in time!";
+ }
+ }
+
+ iovec msg2Iov{msg2.data(), msg2.size()};
+ status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, {});
+ if (status != DEAD_OBJECT)
+ return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
+ "should return DEAD_OBJECT, but it is "
+ << statusToString(status);
+ return AssertionSuccess();
+ };
+
+ auto server = std::make_unique<Server>();
+ ASSERT_TRUE(server->setUp(GetParam()));
+
+ // Set up client
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(GetParam()));
+
+ // Exchange keys
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+
+ server->setPostConnect(serverPostConnect);
+
+ server->start();
+ // connect() to server and do handshake
+ ASSERT_TRUE(client.setUpTransport());
+ // read the first message. This ensures that server has finished handshake and start handling
+ // client fd. Server thread should pause at writeCv.wait_for().
+ ASSERT_TRUE(client.readMessage(RpcTransportTestUtils::kMessage));
+ // Trigger server shutdown after server starts handling client FD. This ensures that the second
+ // write is on an FdTrigger that has been shut down.
+ server->shutdown();
+ // Continues server thread to write the second message.
+ {
+ std::lock_guard<std::mutex> lock(writeMutex);
+ shouldContinueWriting = true;
+ }
+ writeCv.notify_all();
+ // After this line, server thread unblocks and attempts to write the second message, but
+ // shutdown is triggered, so write should failed with DEAD_OBJECT. See |serverPostConnect|.
+ // On the client side, second read fails with DEAD_OBJECT
+ ASSERT_FALSE(client.readMessage(msg2));
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
+ ::testing::ValuesIn(RpcTransportTest::getRpcTranportTestParams()),
+ RpcTransportTest::PrintParamInfo);
+
+class RpcTransportTlsKeyTest
+ : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
+public:
+ template <typename A, typename B>
+ status_t trust(const A& a, const B& b) {
+ auto [socketType, certificateFormat, keyFormat] = GetParam();
+ return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
+ }
+ static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [socketType, certificateFormat, keyFormat] = info.param;
+ auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
+ "_key_" + PrintToString(keyFormat);
+ return ret;
+ };
+};
+
+TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
+ auto [socketType, certificateFormat, keyFormat] = GetParam();
+
+ std::vector<uint8_t> pkeyData, certData;
+ {
+ auto pkey = makeKeyPairForSelfSignedCert();
+ ASSERT_NE(nullptr, pkey);
+ auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
+ ASSERT_NE(nullptr, cert);
+ pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
+ certData = serializeCertificate(cert.get(), certificateFormat);
+ }
+
+ auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
+ auto desCert = deserializeCertificate(certData, certificateFormat);
+ auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
+ auto utilsParam =
+ std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
+
+ auto server = std::make_unique<RpcTransportTestUtils::Server>();
+ ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
+
+ RpcTransportTestUtils::Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp(utilsParam));
+
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+
+ server->start();
+ client.run();
+}
+
+INSTANTIATE_TEST_CASE_P(
+ BinderRpc, RpcTransportTlsKeyTest,
+ testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
+ testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
+ testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
+ RpcTransportTlsKeyTest::PrintParamInfo);
} // 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/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
new file mode 100644
index 0000000..a807afa
--- /dev/null
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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 <android-base/hex.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <binder/Parcel.h>
+#include <binder/RpcSession.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+#include "../Debug.h"
+
+namespace android {
+
+static const int32_t kInt32Array[] = {-1, 0, 17};
+static const uint8_t kByteArray[] = {0, 17, 255};
+enum EnumInt8 : int8_t { Int8A, Int8B };
+enum EnumInt32 : int32_t { Int32A, Int32B };
+enum EnumInt64 : int64_t { Int64A, Int64B };
+struct AParcelable : Parcelable {
+ status_t writeToParcel(Parcel* parcel) const { return parcel->writeInt32(37); }
+ status_t readFromParcel(const Parcel*) { return OK; }
+};
+
+// clang-format off
+constexpr size_t kFillFunIndexLineBase = __LINE__ + 2;
+static const std::vector<std::function<void(Parcel* p)>> kFillFuns {
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInterfaceToken(String16(u"tok"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32(-1)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32(0)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32(17)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint32(0)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint32(1)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint32(10003)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64(-1)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64(0)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64(17)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64(0)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64(1)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64(10003)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloat(0.0f)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloat(0.1f)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloat(9.1f)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDouble(0.0)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDouble(0.1)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDouble(9.1)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCString("")); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCString("a")); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCString("baba")); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString8(String8(""))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString8(String8("a"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString8(String8("baba"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16(String16(u""))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16(String16(u"a"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16(String16(u"baba"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinder(nullptr)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Array(arraysize(kInt32Array), kInt32Array)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteArray(arraysize(kByteArray), kByteArray)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeBool(true)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeBool(false)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeChar('a')); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeChar('?')); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeChar('\0')); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByte(-128)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByte(0)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByte(127)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::string(""))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::string("a"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::string("abab"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::nullopt)); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::optional<std::string>(""))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::optional<std::string>("a"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::optional<std::string>("abab"))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<int8_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<int8_t>>({-1, 0, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<int8_t>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<int8_t>({-1, 0, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<uint8_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<uint8_t>>({0, 1, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<uint8_t>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<uint8_t>({0, 1, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::optional<std::vector<int32_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::optional<std::vector<int32_t>>({-1, 0, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::vector<int32_t>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::vector<int32_t>({-1, 0, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::optional<std::vector<int64_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::optional<std::vector<int64_t>>({-1, 0, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::vector<int64_t>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::vector<int64_t>({-1, 0, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::optional<std::vector<uint64_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::optional<std::vector<uint64_t>>({0, 1, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::vector<uint64_t>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::vector<uint64_t>({0, 1, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::optional<std::vector<float>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::optional<std::vector<float>>({0.0f, 0.1f, 9.1f}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::vector<float>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::vector<float>({0.0f, 0.1f, 9.1f}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::optional<std::vector<double>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::optional<std::vector<double>>({0.0, 0.1, 9.1}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::vector<double>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::vector<double>({0.0, 0.1, 9.1}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::optional<std::vector<bool>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::optional<std::vector<bool>>({true, false}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::vector<bool>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::vector<bool>({true, false}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::optional<std::vector<char16_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::optional<std::vector<char16_t>>({'a', '\0', '?'}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::vector<char16_t>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::vector<char16_t>({'a', '\0', '?'}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::optional<std::vector<std::optional<String16>>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::optional<std::vector<std::optional<String16>>>({std::nullopt, String16(), String16(u"a")}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::vector<std::optional<String16>>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::vector<std::optional<String16>>({std::nullopt, String16(), String16(u"a")}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::optional<std::vector<std::optional<std::string>>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::optional<std::vector<std::optional<std::string>>>({std::nullopt, std::string(), std::string("a")}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::vector<std::optional<std::string>>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::vector<std::optional<std::string>>({std::nullopt, std::string(), std::string("a")}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::optional<std::vector<sp<IBinder>>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::optional<std::vector<sp<IBinder>>>({nullptr}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::vector<sp<IBinder>>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::vector<sp<IBinder>>({nullptr}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt8>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt8>>({Int8A, Int8B}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::vector<EnumInt8>({Int8A, Int8B}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt32>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt32>>({Int32A, Int32B}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::vector<EnumInt32>({Int32A, Int32B}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt64>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt64>>({Int64A, Int64B}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::vector<EnumInt64>({Int64A, Int64B}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelableVector(std::optional<std::vector<std::optional<AParcelable>>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelableVector(std::optional<std::vector<std::optional<AParcelable>>>({AParcelable()}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelableVector(std::vector<AParcelable>({AParcelable()}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeNullableParcelable(std::optional<AParcelable>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeNullableParcelable(std::optional<AParcelable>(AParcelable()))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelable(AParcelable())); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::vector<int32_t>({0, 1, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::vector<AParcelable>({}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::optional<std::vector<int32_t>>(std::nullopt))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::optional<std::vector<int32_t>>({0, 1, 17}))); },
+ [](Parcel* p) { ASSERT_EQ(OK, p->writeNoException()); },
+ [](Parcel* p) { ASSERT_EQ(OK, binder::Status::ok().writeToParcel(p)); },
+ [](Parcel* p) { ASSERT_EQ(OK, binder::Status::fromExceptionCode(7, ":D").writeToParcel(p)); },
+ [](Parcel* p) { ASSERT_EQ(OK, binder::Status::fromServiceSpecificError(8, ":/").writeToParcel(p)); },
+};
+// clang-format on
+
+static void setParcelForRpc(Parcel* p, uint32_t version) {
+ auto session = RpcSession::make();
+ CHECK(session->setProtocolVersion(version));
+ CHECK_EQ(OK, session->addNullDebuggingClient());
+ p->markForRpc(session);
+}
+
+static std::string buildRepr(uint32_t version) {
+ std::string result;
+ for (size_t i = 0; i < kFillFuns.size(); i++) {
+ if (i != 0) result += "|";
+ Parcel p;
+ setParcelForRpc(&p, version);
+ kFillFuns[i](&p);
+
+ result += base::HexString(p.data(), p.dataSize());
+ }
+ return result;
+}
+
+static void checkRepr(const std::string& repr, uint32_t version) {
+ const std::string actualRepr = buildRepr(version);
+
+ auto expected = base::Split(repr, "|");
+ ASSERT_EQ(expected.size(), kFillFuns.size());
+
+ auto actual = base::Split(actualRepr, "|");
+ ASSERT_EQ(actual.size(), kFillFuns.size());
+
+ for (size_t i = 0; i < kFillFuns.size(); i++) {
+ EXPECT_EQ(expected[i], actual[i])
+ << "Format mismatch, see " __FILE__ " line " << (kFillFunIndexLineBase + i);
+ }
+
+ // same check as in the loop, but the above error is more clear to debug,
+ // and this error is more clear to be able to update the source file here.
+ EXPECT_EQ(repr, actualRepr);
+}
+
+const std::string kCurrentRepr =
+ "0300000074006f006b000000|ffffffff|00000000|11000000|00000000|01000000|13270000|"
+ "ffffffffffffffff|0000000000000000|1100000000000000|0000000000000000|0100000000000000|"
+ "1327000000000000|00000000|cdcccc3d|9a991141|0000000000000000|9a9999999999b93f|"
+ "3333333333332240|00000000|61000000|6261626100000000|0000000000000000|0100000061000000|"
+ "040000006261626100000000|0000000000000000|0100000061000000|"
+ "04000000620061006200610000000000|0000000000000000|03000000ffffffff0000000011000000|"
+ "030000000011ff00|01000000|00000000|61000000|3f000000|00000000|80ffffff|00000000|7f000000|"
+ "0000000000000000|0100000061000000|04000000610062006100620000000000|ffffffff|"
+ "0000000000000000|0100000061000000|04000000610062006100620000000000|ffffffff|"
+ "03000000ff001100|00000000|03000000ff001100|ffffffff|0300000000011100|00000000|"
+ "0300000000011100|ffffffff|03000000ffffffff0000000011000000|00000000|"
+ "03000000ffffffff0000000011000000|ffffffff|"
+ "03000000ffffffffffffffff00000000000000001100000000000000|00000000|"
+ "03000000ffffffffffffffff00000000000000001100000000000000|ffffffff|"
+ "03000000000000000000000001000000000000001100000000000000|00000000|"
+ "03000000000000000000000001000000000000001100000000000000|ffffffff|"
+ "0300000000000000cdcccc3d9a991141|00000000|0300000000000000cdcccc3d9a991141|ffffffff|"
+ "0300000000000000000000009a9999999999b93f3333333333332240|00000000|"
+ "0300000000000000000000009a9999999999b93f3333333333332240|ffffffff|"
+ "020000000100000000000000|00000000|020000000100000000000000|ffffffff|"
+ "0300000061000000000000003f000000|00000000|0300000061000000000000003f000000|ffffffff|"
+ "03000000ffffffff00000000000000000100000061000000|00000000|"
+ "03000000ffffffff00000000000000000100000061000000|ffffffff|"
+ "03000000ffffffff00000000000000000100000061000000|00000000|"
+ "03000000ffffffff00000000000000000100000061000000|ffffffff|010000000000000000000000|"
+ "00000000|010000000000000000000000|ffffffff|0200000000010000|0200000000010000|ffffffff|"
+ "020000000000000001000000|020000000000000001000000|ffffffff|"
+ "0200000000000000000000000100000000000000|0200000000000000000000000100000000000000|"
+ "ffffffff|010000000100000025000000|010000000100000025000000|00000000|0100000025000000|"
+ "0100000025000000|03000000|00000000|ffffffff|03000000|00000000|00000000|"
+ "07000000020000003a0044000000000000000000|f8ffffff020000003a002f00000000000000000008000000";
+
+TEST(RpcWire, CurrentVersion) {
+ checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
+}
+
+static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
+ "you better update this test!");
+
+TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
+ if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+ EXPECT_FALSE(base::GetProperty("ro.build.version.codename", "") == "REL")
+ << "Binder RPC wire protocol must be frozen on a release branch!";
+ }
+}
+
+TEST(RpcWire, IfNotExperimentalCodeHasNoExperimentalFeatures) {
+ if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+ GTEST_SKIP() << "Version is experimental, so experimental features are okay.";
+ }
+
+ // if we set the wire protocol version to experimental, none of the code
+ // should introduce a difference (if this fails, it means we have features
+ // which are enabled under experimental mode, but we aren't actually using
+ // or testing them!)
+ checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+}
+
+} // namespace android
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 2ce13df..2398e1e 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -102,7 +102,7 @@
return Status::ok();
}
Status sendAndCallBinder(const sp<IBinder>& binder) override {
- Stability::debugLogStability("sendAndCallBinder got binder", binder);
+ ALOGI("Debug log stability: %s", Stability::debugToString(binder).c_str());
return Status::fromExceptionCode(BadStableBinder::doUserTransaction(binder));
}
Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override {
@@ -197,6 +197,14 @@
}
}
+TEST(BinderStability, ConnectionInfoRequiresManifestEntries) {
+ sp<IServiceManager> sm = android::defaultServiceManager();
+ sp<IBinder> systemBinder = BadStableBinder::system();
+ EXPECT_EQ(OK, sm->addService(String16("no.connection.foo"), systemBinder));
+ std::optional<android::IServiceManager::ConnectionInfo> connectionInfo;
+ connectionInfo = sm->getConnectionInfo(String16("no.connection.foo"));
+ EXPECT_EQ(connectionInfo, std::nullopt);
+}
TEST(BinderStability, CantCallVendorBinderInSystemContext) {
sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer);
auto server = interface_cast<IBinderStabilityTest>(serverBinder);
diff --git a/libs/binder/tests/binderStatusUnitTest.cpp b/libs/binder/tests/binderStatusUnitTest.cpp
new file mode 100644
index 0000000..a32ec5c
--- /dev/null
+++ b/libs/binder/tests/binderStatusUnitTest.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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/Parcel.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+using android::Parcel;
+using android::binder::Status;
+
+TEST(Status, WriteOverParcel) {
+ Status status = Status::fromExceptionCode(Status::EX_NULL_POINTER);
+
+ Parcel indirect;
+ indirect.writeInt32(64);
+ status.writeOverParcel(&indirect);
+
+ Parcel direct;
+ status.writeToParcel(&direct);
+
+ EXPECT_EQ(0, indirect.compareData(direct));
+}
diff --git a/libs/binder/tests/binderUtilsHostTest.cpp b/libs/binder/tests/binderUtilsHostTest.cpp
new file mode 100644
index 0000000..4330e3e
--- /dev/null
+++ b/libs/binder/tests/binderUtilsHostTest.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 <sysexits.h>
+
+#include <chrono>
+
+#include <android-base/result-gmock.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "../UtilsHost.h"
+
+using android::base::testing::Ok;
+using testing::Optional;
+
+namespace android {
+
+TEST(UtilsHost, ExecuteImmediately) {
+ auto result = execute({"echo", "foo"}, nullptr);
+ ASSERT_THAT(result, Ok());
+ EXPECT_THAT(result->exitCode, Optional(EX_OK));
+ EXPECT_EQ(result->stdoutStr, "foo\n");
+}
+
+TEST(UtilsHost, ExecuteLongRunning) {
+ auto now = std::chrono::system_clock::now();
+
+ {
+ std::vector<std::string> args{"sh", "-c",
+ "sleep 0.5 && echo -n f && sleep 0.5 && echo oo && sleep 1"};
+ auto result = execute(std::move(args), [](const CommandResult& commandResult) {
+ return android::base::EndsWith(commandResult.stdoutStr, "\n");
+ });
+ auto elapsed = std::chrono::system_clock::now() - now;
+ auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+ EXPECT_GE(elapsedMs, 1000);
+ EXPECT_LT(elapsedMs, 2000);
+
+ ASSERT_THAT(result, Ok());
+ EXPECT_EQ(std::nullopt, result->exitCode);
+ EXPECT_EQ(result->stdoutStr, "foo\n");
+ }
+
+ // ~CommandResult() called, child process is killed.
+ // Assert that the second sleep does not finish.
+ auto elapsed = std::chrono::system_clock::now() - now;
+ auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+ EXPECT_LT(elapsedMs, 2000);
+}
+
+TEST(UtilsHost, ExecuteLongRunning2) {
+ auto now = std::chrono::system_clock::now();
+
+ {
+ std::vector<std::string> args{"sh", "-c",
+ "sleep 2 && echo -n f && sleep 2 && echo oo && sleep 2"};
+ auto result = execute(std::move(args), [](const CommandResult& commandResult) {
+ return android::base::EndsWith(commandResult.stdoutStr, "\n");
+ });
+ auto elapsed = std::chrono::system_clock::now() - now;
+ auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+ EXPECT_GE(elapsedMs, 4000);
+ EXPECT_LT(elapsedMs, 6000);
+
+ ASSERT_THAT(result, Ok());
+ EXPECT_EQ(std::nullopt, result->exitCode);
+ EXPECT_EQ(result->stdoutStr, "foo\n");
+ }
+
+ // ~CommandResult() called, child process is killed.
+ // Assert that the second sleep does not finish.
+ auto elapsed = std::chrono::system_clock::now() - now;
+ auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
+ EXPECT_LT(elapsedMs, 6000);
+}
+
+TEST(UtilsHost, KillWithSigKill) {
+ std::vector<std::string> args{"sh", "-c", "echo foo && sleep 10"};
+ auto result = execute(std::move(args), [](const CommandResult& commandResult) {
+ // FOR TEST PURPOSE ONLY. DON'T DO THIS!
+ if (commandResult.pid.has_value()) {
+ (void)kill(*commandResult.pid, SIGKILL);
+ }
+ // FOR TEST PURPOSE ONLY. DON'T DO THIS!
+ return false;
+ });
+
+ ASSERT_THAT(result, Ok());
+ EXPECT_EQ(std::nullopt, result->exitCode);
+ EXPECT_THAT(result->signal, Optional(SIGKILL));
+}
+
+} // namespace android
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
new file mode 100644
index 0000000..50d12c4
--- /dev/null
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -0,0 +1,91 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <vector>
+
+#include <binder/RpcAuth.h>
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcCertificateVerifier.h>
+#include <binder/RpcTransport.h>
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+constexpr const uint32_t kCertValidSeconds = 30 * (60 * 60 * 24); // 30 days
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert();
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pKey, uint32_t validSeconds);
+
+// An implementation of RpcAuth that generates a key pair and a self-signed
+// certificate every time configure() is called.
+class RpcAuthSelfSigned : public RpcAuth {
+public:
+ RpcAuthSelfSigned(uint32_t validSeconds = kCertValidSeconds) : mValidSeconds(validSeconds) {}
+ status_t configure(SSL_CTX* ctx) override;
+
+private:
+ const uint32_t mValidSeconds;
+};
+
+class RpcAuthPreSigned : public RpcAuth {
+public:
+ RpcAuthPreSigned(bssl::UniquePtr<EVP_PKEY> pkey, bssl::UniquePtr<X509> cert)
+ : mPkey(std::move(pkey)), mCert(std::move(cert)) {}
+ status_t configure(SSL_CTX* ctx) override;
+
+private:
+ bssl::UniquePtr<EVP_PKEY> mPkey;
+ bssl::UniquePtr<X509> mCert;
+};
+
+// A simple certificate verifier for testing.
+// Keep a list of leaf certificates as trusted. No certificate chain support.
+//
+// All APIs are thread-safe. However, if verify() and addTrustedPeerCertificate() are called
+// simultaneously in different threads, it is not deterministic whether verify() will use the
+// certificate being added.
+class RpcCertificateVerifierSimple : public RpcCertificateVerifier {
+public:
+ status_t verify(const SSL*, uint8_t*) override;
+
+ // Add a trusted peer certificate. Peers presenting this certificate are accepted.
+ //
+ // Caller must ensure that RpcTransportCtx::newTransport() are called after all trusted peer
+ // certificates are added. Otherwise, RpcTransport-s created before may not trust peer
+ // certificates added later.
+ [[nodiscard]] status_t addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert);
+
+private:
+ std::mutex mMutex; // for below
+ std::vector<bssl::UniquePtr<X509>> mTrustedPeerCertificates;
+};
+
+// A RpcCertificateVerifier that does not verify anything.
+class RpcCertificateVerifierNoOp : public RpcCertificateVerifier {
+public:
+ RpcCertificateVerifierNoOp(status_t status) : mStatus(status) {}
+ status_t verify(const SSL*, uint8_t*) override { return mStatus; }
+
+private:
+ status_t mStatus;
+};
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 74b8eb8..57d496d 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -9,7 +9,6 @@
cc_fuzz {
name: "binder_parcel_fuzzer",
- defaults: ["libbinder_ndk_host_user"],
host_supported: true,
fuzz_config: {
@@ -23,18 +22,13 @@
"main.cpp",
"random_fd.cpp",
"random_parcel.cpp",
- "util.cpp",
],
static_libs: [
"libbase",
"libbinder_random_parcel",
- "libcgrouprc",
- "libcgrouprc_format",
"libcutils",
"libhidlbase",
"liblog",
- "libprocessgroup",
- "libjsoncpp",
"libutils",
],
@@ -51,6 +45,9 @@
"libbinder",
],
},
+ darwin: {
+ enabled: false,
+ },
},
// This flag enables verbose output in the fuzz target, and is very useful
// for debugging a failure. If you are trying to diagnose how a crash was
@@ -64,15 +61,18 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
srcs: [
"random_fd.cpp",
"random_parcel.cpp",
+ "libbinder_driver.cpp",
+ "libbinder_ndk_driver.cpp",
],
shared_libs: [
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libutils",
],
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 624def1..47ec776 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -18,11 +18,14 @@
#include "binder.h"
#include "util.h"
+#include <android-base/hex.h>
#include <android/os/IServiceManager.h>
#include <binder/ParcelableHolder.h>
#include <binder/PersistableBundle.h>
+#include <binder/Status.h>
using ::android::status_t;
+using ::android::base::HexString;
enum ByteEnum : int8_t {};
enum IntEnum : int32_t {};
@@ -66,6 +69,10 @@
int32_t mValue = 0;
};
+struct BigStruct {
+ uint8_t data[1337];
+};
+
#define PARCEL_READ_WITH_STATUS(T, FUN) \
[] (const ::android::Parcel& p, uint8_t /*data*/) {\
FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
@@ -94,6 +101,7 @@
PARCEL_READ_NO_STATUS(size_t, dataAvail),
PARCEL_READ_NO_STATUS(size_t, dataPosition),
PARCEL_READ_NO_STATUS(size_t, dataCapacity),
+ PARCEL_READ_NO_STATUS(::android::binder::Status, enforceNoDataAvail),
[] (const ::android::Parcel& p, uint8_t pos) {
FUZZ_LOG() << "about to setDataPosition: " << pos;
p.setDataPosition(pos);
@@ -101,6 +109,8 @@
},
PARCEL_READ_NO_STATUS(size_t, allowFds),
PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
+ PARCEL_READ_NO_STATUS(std::vector<android::sp<android::IBinder>>, debugReadAllStrongBinders),
+ PARCEL_READ_NO_STATUS(std::vector<int>, debugReadAllFileDescriptors),
[] (const ::android::Parcel& p, uint8_t len) {
std::string interface(len, 'a');
FUZZ_LOG() << "about to enforceInterface: " << interface;
@@ -124,7 +134,7 @@
[] (const ::android::Parcel& p, uint8_t len) {
FUZZ_LOG() << "about to readInplace";
const void* r = p.readInplace(len);
- FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << hexString(r, len);
+ FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
},
PARCEL_READ_OPT_STATUS(int32_t, readInt32),
PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
@@ -149,7 +159,7 @@
FUZZ_LOG() << "about to readString8Inplace";
size_t outLen = 0;
const char* str = p.readString8Inplace(&outLen);
- std::string bytes = hexString(str, sizeof(char) * (outLen + 1));
+ std::string bytes = str ? HexString(str, sizeof(char) * (outLen + 1)) : "null";
FUZZ_LOG() << "readString8Inplace: " << bytes << " size: " << outLen;
},
PARCEL_READ_OPT_STATUS(android::String16, readString16),
@@ -159,28 +169,26 @@
FUZZ_LOG() << "about to readString16Inplace";
size_t outLen = 0;
const char16_t* str = p.readString16Inplace(&outLen);
- std::string bytes = hexString(str, sizeof(char16_t) * (outLen + 1));
+ std::string bytes = str ? HexString(str, sizeof(char16_t) * (outLen + 1)) : "null";
FUZZ_LOG() << "readString16Inplace: " << bytes << " size: " << outLen;
},
PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readNullableStrongBinder),
- // TODO(b/131868573): can force read of arbitrarily sized vector
- // PARCEL_READ_WITH_STATUS(std::vector<ByteEnum>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<ByteEnum>>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<ByteEnum>>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::vector<IntEnum>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<IntEnum>>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<IntEnum>>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::vector<LongEnum>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<LongEnum>>, readEnumVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<LongEnum>>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::vector<ByteEnum>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<ByteEnum>>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<ByteEnum>>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::vector<IntEnum>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<IntEnum>>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<IntEnum>>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::vector<LongEnum>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<LongEnum>>, readEnumVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<LongEnum>>, readEnumVector),
// only reading one parcelable type for now
- // TODO(b/131868573): can force read of arbitrarily sized vector
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<ExampleParcelable>>>, readParcelableVector),
- // PARCEL_READ_WITH_STATUS(std::vector<ExampleParcelable>, readParcelableVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<ExampleParcelable>>>, readParcelableVector),
+ PARCEL_READ_WITH_STATUS(std::vector<ExampleParcelable>, readParcelableVector),
PARCEL_READ_WITH_STATUS(ExampleParcelable, readParcelable),
PARCEL_READ_WITH_STATUS(std::unique_ptr<ExampleParcelable>, readParcelable),
PARCEL_READ_WITH_STATUS(std::optional<ExampleParcelable>, readParcelable),
@@ -188,46 +196,72 @@
// only reading one binder type for now
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readNullableStrongBinder),
+ PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::os::IServiceManager>>, readStrongBinderVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::sp<android::os::IServiceManager>>>, readStrongBinderVector),
- // TODO(b/131868573): can force read of arbitrarily sized vector
- // PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
- // PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
- // PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::IBinder>>, readStrongBinderVector),
+ PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
+ PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
+ PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::IBinder>>, readStrongBinderVector),
- // TODO(b/131868573): can force read of arbitrarily sized vector
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int8_t>>, readByteVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int8_t>>, readByteVector),
- // PARCEL_READ_WITH_STATUS(std::vector<int8_t>, readByteVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, readByteVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint8_t>>, readByteVector),
- // PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, readByteVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int32_t>>, readInt32Vector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int32_t>>, readInt32Vector),
- // PARCEL_READ_WITH_STATUS(std::vector<int32_t>, readInt32Vector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int64_t>>, readInt64Vector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int64_t>>, readInt64Vector),
- // PARCEL_READ_WITH_STATUS(std::vector<int64_t>, readInt64Vector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint64_t>>, readUint64Vector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint64_t>>, readUint64Vector),
- // PARCEL_READ_WITH_STATUS(std::vector<uint64_t>, readUint64Vector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<float>>, readFloatVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<float>>, readFloatVector),
- // PARCEL_READ_WITH_STATUS(std::vector<float>, readFloatVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<double>>, readDoubleVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<double>>, readDoubleVector),
- // PARCEL_READ_WITH_STATUS(std::vector<double>, readDoubleVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<bool>>, readBoolVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<bool>>, readBoolVector),
- // PARCEL_READ_WITH_STATUS(std::vector<bool>, readBoolVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<char16_t>>, readCharVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<char16_t>>, readCharVector),
- // PARCEL_READ_WITH_STATUS(std::vector<char16_t>, readCharVector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<android::String16>>>, readString16Vector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<android::String16>>>, readString16Vector),
- // PARCEL_READ_WITH_STATUS(std::vector<android::String16>, readString16Vector),
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<std::string>>>, readUtf8VectorFromUtf16Vector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<std::string>>>, readUtf8VectorFromUtf16Vector),
- // PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int8_t>>, readByteVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<int8_t>>, readByteVector),
+ PARCEL_READ_WITH_STATUS(std::vector<int8_t>, readByteVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, readByteVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint8_t>>, readByteVector),
+ PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, readByteVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int32_t>>, readInt32Vector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<int32_t>>, readInt32Vector),
+ PARCEL_READ_WITH_STATUS(std::vector<int32_t>, readInt32Vector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int64_t>>, readInt64Vector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<int64_t>>, readInt64Vector),
+ PARCEL_READ_WITH_STATUS(std::vector<int64_t>, readInt64Vector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint64_t>>, readUint64Vector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint64_t>>, readUint64Vector),
+ PARCEL_READ_WITH_STATUS(std::vector<uint64_t>, readUint64Vector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<float>>, readFloatVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<float>>, readFloatVector),
+ PARCEL_READ_WITH_STATUS(std::vector<float>, readFloatVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<double>>, readDoubleVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<double>>, readDoubleVector),
+ PARCEL_READ_WITH_STATUS(std::vector<double>, readDoubleVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<bool>>, readBoolVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<bool>>, readBoolVector),
+ PARCEL_READ_WITH_STATUS(std::vector<bool>, readBoolVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<char16_t>>, readCharVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<char16_t>>, readCharVector),
+ PARCEL_READ_WITH_STATUS(std::vector<char16_t>, readCharVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<android::String16>>>, readString16Vector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<android::String16>>>, readString16Vector),
+ PARCEL_READ_WITH_STATUS(std::vector<android::String16>, readString16Vector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<std::string>>>, readUtf8VectorFromUtf16Vector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<std::string>>>, readUtf8VectorFromUtf16Vector),
+ PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
+
+#define COMMA ,
+ PARCEL_READ_WITH_STATUS(std::array<uint8_t COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<uint8_t COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<char16_t COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<char16_t COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<std::string COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<std::optional<std::string> COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<android::String16 COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<std::optional<android::String16> COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<android::sp<android::IBinder> COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<android::sp<android::IBinder> COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<ExampleParcelable COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<std::optional<ExampleParcelable> COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<ByteEnum COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<ByteEnum COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<IntEnum COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<IntEnum COMMA 3>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<LongEnum COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<LongEnum COMMA 3>>, readFixedArray),
+ // nested arrays
+ PARCEL_READ_WITH_STATUS(std::array<std::array<uint8_t COMMA 3> COMMA 4>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<uint8_t COMMA 3> COMMA 4>>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::array<ExampleParcelable COMMA 3>, readFixedArray),
+ PARCEL_READ_WITH_STATUS(std::optional<std::array<std::array<std::optional<ExampleParcelable> COMMA 3> COMMA 4>>, readFixedArray),
+#undef COMMA
[] (const android::Parcel& p, uint8_t /*len*/) {
FUZZ_LOG() << "about to read flattenable";
@@ -242,8 +276,12 @@
FUZZ_LOG() << "read lite flattenable: " << status;
},
- // TODO(b/131868573): can force read of arbitrarily sized vector
- // TODO: resizeOutVector
+ PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, resizeOutVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint8_t>>, resizeOutVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, resizeOutVector),
+ PARCEL_READ_WITH_STATUS(std::vector<BigStruct>, resizeOutVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<BigStruct>>, resizeOutVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<BigStruct>>, resizeOutVector),
PARCEL_READ_NO_STATUS(int32_t, readExceptionCode),
[] (const android::Parcel& p, uint8_t /*len*/) {
@@ -261,10 +299,9 @@
PARCEL_READ_NO_STATUS(int, readParcelFileDescriptor),
PARCEL_READ_WITH_STATUS(android::base::unique_fd, readUniqueFileDescriptor),
- // TODO(b/131868573): can force read of arbitrarily sized vector
- // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
- // PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
- // PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
+ PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
+ PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
[] (const android::Parcel& p, uint8_t len) {
FUZZ_LOG() << "about to readBlob";
@@ -279,7 +316,6 @@
FUZZ_LOG() << "readObject: " << obj;
},
PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
- PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
// additional parcelable objects defined in libbinder
@@ -296,6 +332,23 @@
FUZZ_LOG() << "ParcelableHolder status: " << status;
},
PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
+ [] (const ::android::Parcel& p, uint8_t /* data */) {
+ FUZZ_LOG() << "about to call hasFileDescriptorsInRange() with status";
+ size_t offset = p.readUint32();
+ size_t length = p.readUint32();
+ bool result;
+ status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
+ FUZZ_LOG() << " status: " << status << " result: " << result;
+ },
+ [] (const ::android::Parcel& p, uint8_t /* data */) {
+ FUZZ_LOG() << "about to call compareDataInRange() with status";
+ size_t thisOffset = p.readUint32();
+ size_t otherOffset = p.readUint32();
+ size_t length = p.readUint32();
+ int result;
+ status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
+ FUZZ_LOG() << " status: " << status << " result: " << result;
+ },
};
// clang-format on
#pragma clang diagnostic pop
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 008780c..5aeb5cc 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -25,6 +25,7 @@
// TODO(b/142061461): parent class
class SomeParcelable {
public:
+ binder_status_t writeToParcel(AParcel* /*parcel*/) { return STATUS_OK; }
binder_status_t readFromParcel(const AParcel* parcel) {
return AParcel_readInt32(parcel, &mValue);
}
@@ -33,6 +34,41 @@
int32_t mValue = 0;
};
+class ISomeInterface : public ::ndk::ICInterface {
+public:
+ ISomeInterface() = default;
+ virtual ~ISomeInterface() = default;
+ static binder_status_t readFromParcel(const AParcel* parcel,
+ std::shared_ptr<ISomeInterface>* instance);
+};
+
+static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) {
+ return STATUS_UNKNOWN_TRANSACTION;
+}
+
+static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+
+class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
+public:
+ explicit BpSomeInterface(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}
+ virtual ~BpSomeInterface() = default;
+};
+
+binder_status_t ISomeInterface::readFromParcel(const AParcel* parcel,
+ std::shared_ptr<ISomeInterface>* instance) {
+ ::ndk::SpAIBinder binder;
+ binder_status_t status = AParcel_readStrongBinder(parcel, binder.getR());
+ if (status == STATUS_OK) {
+ if (AIBinder_associateClass(binder.get(), g_class)) {
+ *instance = std::static_pointer_cast<ISomeInterface>(
+ ::ndk::ICInterface::asInterface(binder.get()));
+ } else {
+ *instance = ::ndk::SharedRefBase::make<BpSomeInterface>(binder);
+ }
+ }
+ return status;
+}
+
#define PARCEL_READ(T, FUN) \
[](const NdkParcelAdapter& p, uint8_t /*data*/) { \
FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
@@ -91,28 +127,50 @@
PARCEL_READ(ndk::ScopedFileDescriptor, ndk::AParcel_readRequiredParcelFileDescriptor),
PARCEL_READ(std::string, ndk::AParcel_readString),
PARCEL_READ(std::optional<std::string>, ndk::AParcel_readString),
- // TODO(b/131868573): can force process to allocate arbitrary amount of
- // memory
- // PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>,
- // ndk::AParcel_readVector), PARCEL_READ(std::vector<SomeParcelable>,
- // ndk::AParcel_readVector), PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<uint32_t>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<int64_t>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<int64_t>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<uint64_t>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<uint64_t>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<float>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<float>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<double>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<double>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<bool>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<bool>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<char16_t>, ndk::AParcel_readVector),
- // PARCEL_READ(std::optional<std::vector<char16_t>>, ndk::AParcel_readVector),
- // PARCEL_READ(std::vector<int32_t>, ndk::AParcel_resizeVector),
- // PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_resizeVector),
+
+ PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<SomeParcelable>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<std::optional<SomeParcelable>>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<ndk::SpAIBinder>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<ndk::SpAIBinder>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<ndk::ScopedFileDescriptor>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<ndk::ScopedFileDescriptor>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<std::shared_ptr<ISomeInterface>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<std::shared_ptr<ISomeInterface>>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<uint32_t>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<int64_t>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<int64_t>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<uint64_t>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<uint64_t>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<float>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<float>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<double>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<double>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<bool>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<bool>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<char16_t>, ndk::AParcel_readVector),
+ PARCEL_READ(std::optional<std::vector<char16_t>>, ndk::AParcel_readVector),
+ PARCEL_READ(std::vector<int32_t>, ndk::AParcel_resizeVector),
+ PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_resizeVector),
+
+ // methods for std::array<T,N>
+#define COMMA ,
+ PARCEL_READ(std::array<bool COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<uint8_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<char16_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<int32_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<int64_t COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<float COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<double COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<std::string COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<SomeParcelable COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<ndk::SpAIBinder COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<ndk::ScopedFileDescriptor COMMA 3>, ndk::AParcel_readData),
+ PARCEL_READ(std::array<std::shared_ptr<ISomeInterface> COMMA 3>, ndk::AParcel_readData),
+#undef COMMA
};
// clang-format on
diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
index 0fec393..ee9840f 100644
--- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
@@ -18,10 +18,12 @@
#include "hwbinder.h"
#include "util.h"
+#include <android-base/hex.h>
#include <android-base/logging.h>
#include <hwbinder/Parcel.h>
using ::android::status_t;
+using ::android::base::HexString;
// TODO: support scatter-gather types
@@ -70,13 +72,13 @@
FUZZ_LOG() << "about to read";
std::vector<uint8_t> data (length);
status_t status = p.read(data.data(), length);
- FUZZ_LOG() << "read status: " << status << " data: " << hexString(data.data(), data.size());
+ FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
},
[] (const ::android::hardware::Parcel& p, uint8_t length) {
FUZZ_LOG() << "about to read";
std::vector<uint8_t> data (length);
const void* inplace = p.readInplace(length);
- FUZZ_LOG() << "read status: " << hexString(inplace, length);
+ FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
},
PARCEL_READ_WITH_STATUS(int8_t, readInt8),
PARCEL_READ_WITH_STATUS(uint8_t, readUint8),
@@ -100,7 +102,7 @@
FUZZ_LOG() << "about to readString16Inplace";
size_t outSize = 0;
const char16_t* str = p.readString16Inplace(&outSize);
- FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outSize);
+ FUZZ_LOG() << "readString16Inplace: " << HexString(str, sizeof(char16_t) * outSize);
},
PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
@@ -148,28 +150,6 @@
// should be null since we don't create any IPC objects
CHECK(data == nullptr) << data;
},
- [] (const ::android::hardware::Parcel& p, uint8_t size) {
- FUZZ_LOG() << "about to readEmbeddedNativeHandle";
- size_t parent_buffer_handle = size & 0xf;
- size_t parent_offset = size >> 4;
- const native_handle_t* handle = nullptr;
- status_t status = p.readEmbeddedNativeHandle(parent_buffer_handle, parent_offset, &handle);
- FUZZ_LOG() << "readEmbeddedNativeHandle status: " << status << " handle: " << handle << " handle: " << handle;
-
- // should be null since we don't create any IPC objects
- CHECK(handle == nullptr) << handle;
- },
- [] (const ::android::hardware::Parcel& p, uint8_t size) {
- FUZZ_LOG() << "about to readNullableEmbeddedNativeHandle";
- size_t parent_buffer_handle = size & 0xf;
- size_t parent_offset = size >> 4;
- const native_handle_t* handle = nullptr;
- status_t status = p.readNullableEmbeddedNativeHandle(parent_buffer_handle, parent_offset, &handle);
- FUZZ_LOG() << "readNullableEmbeddedNativeHandle status: " << status << " handle: " << handle << " handle: " << handle;
-
- // should be null since we don't create any IPC objects
- CHECK(handle == nullptr) << handle;
- },
[] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
FUZZ_LOG() << "about to readNativeHandleNoDup";
const native_handle_t* handle = nullptr;
@@ -180,14 +160,5 @@
CHECK(handle == nullptr) << handle;
CHECK(status != ::android::OK);
},
- [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
- FUZZ_LOG() << "about to readNullableNativeHandleNoDup";
- const native_handle_t* handle = nullptr;
- status_t status = p.readNullableNativeHandleNoDup(&handle);
- FUZZ_LOG() << "readNullableNativeHandleNoDup status: " << status << " handle: " << handle;
-
- // should be null since we don't create any IPC objects
- CHECK(handle == nullptr) << handle;
- },
};
// clang-format on
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
new file mode 100644
index 0000000..a9a6197
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ * FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ * // can use provider here to create a service with different options
+ * sp<IFoo> myService = sp<IFoo>::make(...);
+ * fuzzService(myService, std::move(provider));
+ * }
+ */
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
new file mode 100644
index 0000000..f2b7823
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+/**
+ * Based on the random data in provider, construct an arbitrary number of
+ * Parcel objects and send them to the service in serial.
+ *
+ * Usage:
+ *
+ * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ * FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+ * // can use provider here to create a service with different options
+ * std::shared_ptr<IFoo> myService = ndk::SharedRefBase<IFoo>::make(...);
+ * fuzzService(myService->asBinder().get(), std::move(provider));
+ * }
+ */
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 0a083d7..843b6e3 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -16,12 +16,13 @@
#pragma once
+#include <android-base/unique_fd.h>
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
-// ownership to callee, always valid or aborts
+// always valid or aborts
// get a random FD for use in fuzzing, of a few different specific types
-int getRandomFd(FuzzedDataProvider* provider);
+base::unique_fd getRandomFd(FuzzedDataProvider* provider);
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 749bf21..459fb12 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -19,13 +19,24 @@
#include <binder/Parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <functional>
+#include <vector>
+
namespace android {
+
+struct RandomParcelOptions {
+ std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader;
+ std::vector<sp<IBinder>> extraBinders;
+ std::vector<base::unique_fd> extraFds;
+};
+
/**
* Fill parcel data, including some random binder objects and FDs
+ *
+ * p - the Parcel to fill
+ * provider - takes ownership and completely consumes provider
+ * writeHeader - optional function to write a specific header once the format of the parcel is
+ * picked (for instance, to write an interface header)
*/
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-/**
- * Fill parcel data, but don't fill any objects.
- */
-void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
new file mode 100644
index 0000000..d5aa353
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_driver.h>
+
+#include <fuzzbinder/random_parcel.h>
+
+namespace android {
+
+void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
+ sp<IBinder> target;
+
+ RandomParcelOptions options{
+ .extraBinders = {binder},
+ .extraFds = {},
+ };
+
+ while (provider.remaining_bytes() > 0) {
+ uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ uint32_t flags = provider.ConsumeIntegral<uint32_t>();
+ Parcel data;
+
+ sp<IBinder> target = options.extraBinders.at(
+ provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
+ options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) {
+ // most code will be behind checks that the head of the Parcel
+ // is exactly this, so make it easier for fuzzers to reach this
+ if (provider.ConsumeBool()) {
+ p->writeInterfaceToken(target->getInterfaceDescriptor());
+ }
+ };
+
+ std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
+ provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+ fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+
+ Parcel reply;
+ (void)target->transact(code, data, &reply, flags);
+
+ // feed back in binders and fds that are returned from the service, so that
+ // we can fuzz those binders, and use the fds and binders to feed back into
+ // the binders
+ auto retBinders = reply.debugReadAllStrongBinders();
+ options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(),
+ retBinders.end());
+ auto retFds = reply.debugReadAllFileDescriptors();
+ for (size_t i = 0; i < retFds.size(); i++) {
+ options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
new file mode 100644
index 0000000..462ef9a
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_parcel.h>
+
+// 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/ibinder_internal.h"
+
+namespace android {
+
+void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) {
+ fuzzService(binder->getBinder(), std::move(provider));
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index a47b753..f435dae 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -22,8 +22,10 @@
#include <iostream>
+#include <android-base/hex.h>
#include <android-base/logging.h>
-#include <binder/RpcSession.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_libbinder.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
@@ -33,8 +35,8 @@
#include <sys/time.h>
using android::fillRandomParcel;
-using android::RpcSession;
using android::sp;
+using android::base::HexString;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
// TODO: functionality to create random parcels for libhwbinder parcels
@@ -46,9 +48,22 @@
fillRandomParcel(p->parcel(), std::move(provider));
}
+template <typename P, typename B>
+void doTransactFuzz(const char* backend, const sp<B>& binder, FuzzedDataProvider&& provider) {
+ uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ uint32_t flag = provider.ConsumeIntegral<uint32_t>();
+
+ FUZZ_LOG() << "backend: " << backend;
+
+ P reply;
+ P data;
+ fillRandomParcel(&data, std::move(provider));
+ (void)binder->transact(code, data, &reply, flag);
+}
+
template <typename P>
-void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
- FuzzedDataProvider&& provider) {
+void doReadFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
+ FuzzedDataProvider&& provider) {
// Allow some majority of the bytes to be dedicated to telling us what to
// do. The fixed value added here represents that we want to test doing a
// lot of 'instructions' even on really short parcels.
@@ -59,25 +74,14 @@
provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
P p;
- if constexpr (std::is_same_v<P, android::Parcel>) {
- if (provider.ConsumeBool()) {
- auto session = sp<RpcSession>::make();
- CHECK(session->addNullDebuggingClient());
- p.markForRpc(session);
- fillRandomParcelData(&p, std::move(provider));
- } else {
- fillRandomParcel(&p, std::move(provider));
- }
- } else {
- fillRandomParcel(&p, std::move(provider));
- }
+ fillRandomParcel(&p, std::move(provider));
// since we are only using a byte to index
CHECK(reads.size() <= 255) << reads.size();
FUZZ_LOG() << "backend: " << backend;
- FUZZ_LOG() << "input: " << hexString(p.data(), p.dataSize());
- FUZZ_LOG() << "instructions: " << hexString(instructions);
+ FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
+ FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
uint8_t a = instructions[i];
@@ -95,25 +99,18 @@
}
}
-size_t getHardMemoryLimit() {
- struct rlimit limit;
- CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
- return limit.rlim_max;
+void* NothingClass_onCreate(void* args) {
+ return args;
}
-
-void setMemoryLimit(size_t cur, size_t max) {
- const struct rlimit kLimit = {
- .rlim_cur = cur,
- .rlim_max = max,
- };
- CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+void NothingClass_onDestroy(void* /*userData*/) {}
+binder_status_t NothingClass_onTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) {
+ return STATUS_UNKNOWN_ERROR;
}
+static AIBinder_Class* kNothingClass =
+ AIBinder_Class_define("nothing", NothingClass_onCreate, NothingClass_onDestroy,
+ NothingClass_onTransact);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- static constexpr size_t kMemLimit = 1 * 1024 * 1024;
- size_t hardLimit = getHardMemoryLimit();
- setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
-
if (size <= 1) return 0; // no use
// avoid timeouts, see b/142617274, b/142473153
@@ -121,24 +118,39 @@
FuzzedDataProvider provider = FuzzedDataProvider(data, size);
- const std::function<void(FuzzedDataProvider &&)> fuzzBackend[3] = {
+ const std::function<void(FuzzedDataProvider &&)> fuzzBackend[] = {
[](FuzzedDataProvider&& provider) {
- doFuzz<::android::hardware::Parcel>("hwbinder", HWBINDER_PARCEL_READ_FUNCTIONS,
- std::move(provider));
+ doTransactFuzz<
+ ::android::hardware::Parcel>("hwbinder",
+ sp<::android::hardware::BHwBinder>::make(),
+ std::move(provider));
},
[](FuzzedDataProvider&& provider) {
- doFuzz<::android::Parcel>("binder", BINDER_PARCEL_READ_FUNCTIONS,
- std::move(provider));
+ doTransactFuzz<::android::Parcel>("binder", sp<::android::BBinder>::make(),
+ std::move(provider));
},
[](FuzzedDataProvider&& provider) {
- doFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
- std::move(provider));
+ // fuzz from the libbinder layer since it's a superset of the
+ // interface you get at the libbinder_ndk layer
+ auto ndkBinder = ndk::SpAIBinder(AIBinder_new(kNothingClass, nullptr));
+ auto binder = AIBinder_toPlatformBinder(ndkBinder.get());
+ doTransactFuzz<::android::Parcel>("binder_ndk", binder, std::move(provider));
+ },
+ [](FuzzedDataProvider&& provider) {
+ doReadFuzz<::android::hardware::Parcel>("hwbinder", HWBINDER_PARCEL_READ_FUNCTIONS,
+ std::move(provider));
+ },
+ [](FuzzedDataProvider&& provider) {
+ doReadFuzz<::android::Parcel>("binder", BINDER_PARCEL_READ_FUNCTIONS,
+ std::move(provider));
+ },
+ [](FuzzedDataProvider&& provider) {
+ doReadFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
+ std::move(provider));
},
};
provider.PickValueInArray(fuzzBackend)(std::move(provider));
- setMemoryLimit(hardLimit, hardLimit);
-
return 0;
}
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index cef6adb..ab0b7e3 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,13 @@
namespace android {
-int getRandomFd(FuzzedDataProvider* provider) {
+base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
int fd = provider->PickValueInArray<std::function<int()>>({
[]() { return ashmem_create_region("binder test region", 1024); },
[]() { return open("/dev/null", O_RDWR); },
})();
CHECK(fd >= 0);
- return fd;
+ return base::unique_fd(fd);
}
} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index b045a22..0204f5e 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -18,6 +18,8 @@
#include <android-base/logging.h>
#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransportRaw.h>
#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
@@ -32,7 +34,30 @@
String16 mDescriptor;
};
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
+static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) {
+ std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes());
+ CHECK(OK == p->write(data.data(), data.size()));
+}
+
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
+ const RandomParcelOptions& options) {
+ if (provider.ConsumeBool()) {
+ auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ CHECK_EQ(OK, session->addNullDebuggingClient());
+ p->markForRpc(session);
+
+ if (options.writeHeader) {
+ options.writeHeader(p, provider);
+ }
+
+ fillRandomParcelData(p, std::move(provider));
+ return;
+ }
+
+ if (options.writeHeader) {
+ options.writeHeader(p, provider);
+ }
+
while (provider.remaining_bytes() > 0) {
auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
// write data
@@ -44,8 +69,16 @@
},
// write FD
[&]() {
- int fd = getRandomFd(&provider);
- CHECK(OK == p->writeFileDescriptor(fd, true /*takeOwnership*/));
+ if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
+ const base::unique_fd& fd = options.extraFds.at(
+ provider.ConsumeIntegralInRange<size_t>(0,
+ options.extraFds.size() -
+ 1));
+ CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
+ } else {
+ base::unique_fd fd = getRandomFd(&provider);
+ CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+ }
},
// write binder
[&]() {
@@ -64,7 +97,15 @@
// candidate for checking usage of an actual BpBinder
return IInterface::asBinder(defaultServiceManager());
},
- []() { return nullptr; },
+ [&]() -> sp<IBinder> {
+ if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
+ return options.extraBinders.at(
+ provider.ConsumeIntegralInRange<
+ size_t>(0, options.extraBinders.size() - 1));
+ } else {
+ return nullptr;
+ }
+ },
});
sp<IBinder> binder = makeFunc();
CHECK(OK == p->writeStrongBinder(binder));
@@ -75,9 +116,4 @@
}
}
-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/tests/parcel_fuzzer/util.cpp b/libs/binder/tests/parcel_fuzzer/util.cpp
deleted file mode 100644
index 479f406..0000000
--- a/libs/binder/tests/parcel_fuzzer/util.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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 FUZZ_LOG_TAG "util"
-#include "util.h"
-
-#include <android-base/logging.h>
-
-#include <iomanip>
-#include <sstream>
-
-std::string hexString(const void* bytes, size_t len) {
- if (bytes == nullptr) return "<null>";
-
- const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
- 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;
-}
-std::string hexString(const std::vector<uint8_t>& bytes) {
- return hexString(bytes.data(), bytes.size());
-}
diff --git a/libs/binder/tests/parcel_fuzzer/util.h b/libs/binder/tests/parcel_fuzzer/util.h
index 45e8c57..a5d0dae 100644
--- a/libs/binder/tests/parcel_fuzzer/util.h
+++ b/libs/binder/tests/parcel_fuzzer/util.h
@@ -49,6 +49,3 @@
FuzzLog& log() { return *this; }
};
#endif
-
-std::string hexString(const void* bytes, size_t len);
-std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index 1c75306..71e847f 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -14,27 +14,41 @@
fuzz_config: {
cc: ["smoreland@google.com"],
},
+ corpus: ["corpus/*"],
+ dictionary: "binder_rpc_fuzzer.dict",
srcs: [
"main.cpp",
],
+ // Not using libbinder_tls_shared_deps to use deterministic boringssl libraries.
static_libs: [
"libbase",
"libcutils",
"liblog",
- "libutils",
+ "libbinder_tls_static",
+ "libbinder_tls_test_utils",
+ "libssl_fuzz_unsafe",
+ "libcrypto_fuzz_unsafe",
],
-
+ cflags: [
+ "-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE" // for RAND_reset_for_fuzzing
+ ],
target: {
android: {
shared_libs: [
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder",
+ "libutils",
],
},
},
+ data: [
+ "server.crt",
+ "server.key",
+ ],
}
diff --git a/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict b/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict
new file mode 100644
index 0000000..b110a02
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict
@@ -0,0 +1,2 @@
+# connection okay header
+"cci"
diff --git a/libs/binder/tests/rpc_fuzzer/corpus/special_transaction b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
new file mode 100644
index 0000000..37228ee
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
Binary files differ
diff --git a/libs/binder/tests/rpc_fuzzer/corpus/transact_on_binder b/libs/binder/tests/rpc_fuzzer/corpus/transact_on_binder
new file mode 100644
index 0000000..ae081e6
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/corpus/transact_on_binder
Binary files differ
diff --git a/libs/binder/tests/rpc_fuzzer/create_certs.sh b/libs/binder/tests/rpc_fuzzer/create_certs.sh
new file mode 100755
index 0000000..4ae4cb1
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/create_certs.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# As explained in
+# https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca
+
+openssl genrsa -des3 -passout pass:xxxx -out server.pass.key 2048
+openssl rsa -passin pass:xxxx -in server.pass.key -out server.key
+rm -f server.pass.key
+
+openssl req \
+ -subj "/" \
+ -new -key server.key -out server.csr
+
+openssl x509 -req -sha256 -days 99999 -in server.csr -signkey server.key -out server.crt
+rm -f server.csr
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 3603ebe..a8713a2 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -13,13 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/Binder.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
#include <sys/resource.h>
#include <sys/un.h>
@@ -29,20 +36,6 @@
static const std::string kSock = std::string(getenv("TMPDIR") ?: "/tmp") +
"/binderRpcFuzzerSocket_" + std::to_string(getpid());
-size_t getHardMemoryLimit() {
- struct rlimit limit;
- CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
- return limit.rlim_max;
-}
-
-void setMemoryLimit(size_t cur, size_t max) {
- const struct rlimit kLimit = {
- .rlim_cur = cur,
- .rlim_max = max,
- };
- CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
-}
-
class SomeBinder : public BBinder {
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {
(void)flags;
@@ -65,21 +58,70 @@
}
};
+int passwordCallback(char* buf, int size, int /*rwflag*/, void* /*u*/) {
+ constexpr const char pass[] = "xxxx"; // See create_certs.sh
+ if (size <= 0) return 0;
+ int numCopy = std::min<int>(size, sizeof(pass));
+ (void)memcpy(buf, pass, numCopy);
+ return numCopy;
+}
+
+struct ServerAuth {
+ bssl::UniquePtr<EVP_PKEY> pkey;
+ bssl::UniquePtr<X509> cert;
+};
+
+// Use pre-configured keys because runtime generated keys / certificates are not
+// deterministic, and the algorithm is time consuming.
+ServerAuth readServerKeyAndCert() {
+ ServerAuth ret;
+
+ auto keyPath = android::base::GetExecutableDirectory() + "/data/server.key";
+ bssl::UniquePtr<BIO> keyBio(BIO_new_file(keyPath.c_str(), "r"));
+ ret.pkey.reset(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, passwordCallback, nullptr));
+ CHECK_NE(ret.pkey.get(), nullptr);
+
+ auto certPath = android::base::GetExecutableDirectory() + "/data/server.crt";
+ bssl::UniquePtr<BIO> certBio(BIO_new_file(certPath.c_str(), "r"));
+ ret.cert.reset(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
+ CHECK_NE(ret.cert.get(), nullptr);
+
+ return ret;
+}
+
+std::unique_ptr<RpcAuth> createServerRpcAuth() {
+ static auto sAuth = readServerKeyAndCert();
+
+ CHECK(EVP_PKEY_up_ref(sAuth.pkey.get()));
+ bssl::UniquePtr<EVP_PKEY> pkey(sAuth.pkey.get());
+ CHECK(X509_up_ref(sAuth.cert.get()));
+ bssl::UniquePtr<X509> cert(sAuth.cert.get());
+
+ return std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
+}
+
+std::unique_ptr<RpcTransportCtxFactory> makeTransportCtxFactory(FuzzedDataProvider* provider) {
+ bool isTls = provider->ConsumeBool();
+ if (!isTls) {
+ return RpcTransportCtxFactoryRaw::make();
+ }
+ status_t verifyStatus = provider->ConsumeIntegral<status_t>();
+ auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(verifyStatus);
+ return RpcTransportCtxFactoryTls::make(verifier, createServerRpcAuth());
+}
+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size > 50000) return 0;
+ FuzzedDataProvider provider(data, size);
+ RAND_reset_for_fuzzing();
unlink(kSock.c_str());
- sp<RpcServer> server = RpcServer::make();
+ sp<RpcServer> server = RpcServer::make(makeTransportCtxFactory(&provider));
server->setRootObject(sp<SomeBinder>::make());
- server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
- CHECK(server->setupUnixDomainServer(kSock.c_str()));
+ CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
- static constexpr size_t kMemLimit = 1llu * 1024 * 1024 * 1024;
- size_t hardLimit = getHardMemoryLimit();
- setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
-
- std::thread serverThread([=] { (void)server->acceptOne(); });
+ std::thread serverThread([=] { (void)server->join(); });
sockaddr_un addr{
.sun_family = AF_UNIX,
@@ -87,33 +129,46 @@
CHECK_LT(kSock.size(), sizeof(addr.sun_path));
memcpy(&addr.sun_path, kSock.c_str(), kSock.size());
- base::unique_fd clientFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
- CHECK_NE(clientFd.get(), -1);
- CHECK_EQ(0,
- TEMP_FAILURE_RETRY(
- connect(clientFd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))))
- << strerror(errno);
+ std::vector<base::unique_fd> connections;
- serverThread.join();
+ bool hangupBeforeShutdown = provider.ConsumeBool();
- // TODO(b/182938024): fuzz multiple sessions, instead of just one
+ while (provider.remaining_bytes() > 0) {
+ if (connections.empty() || provider.ConsumeBool()) {
+ base::unique_fd fd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+ CHECK_NE(fd.get(), -1);
+ CHECK_EQ(0,
+ TEMP_FAILURE_RETRY(
+ connect(fd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))))
+ << strerror(errno);
+ connections.push_back(std::move(fd));
+ } else {
+ size_t idx = provider.ConsumeIntegralInRange<size_t>(0, connections.size() - 1);
-#if 0
- // make fuzzer more productive locally by forcing it to create a new session
- int32_t id = -1;
- CHECK(base::WriteFully(clientFd, &id, sizeof(id)));
-#endif
-
- CHECK(base::WriteFully(clientFd, data, size));
-
- clientFd.reset();
-
- // TODO(b/185167543): better way to force a server to shutdown
- while (!server->listSessions().empty() && server->numUninitializedSessions()) {
- usleep(1);
+ if (provider.ConsumeBool()) {
+ std::string writeData = provider.ConsumeRandomLengthString();
+ ssize_t size = TEMP_FAILURE_RETRY(send(connections.at(idx).get(), writeData.data(),
+ writeData.size(), MSG_NOSIGNAL));
+ CHECK(errno == EPIPE || size == writeData.size())
+ << size << " " << writeData.size() << " " << strerror(errno);
+ } else {
+ connections.erase(connections.begin() + idx); // hang up
+ }
+ }
}
- setMemoryLimit(hardLimit, hardLimit);
+ usleep(10000);
+
+ if (hangupBeforeShutdown) {
+ connections.clear();
+ while (!server->listSessions().empty() || server->numUninitializedSessions()) {
+ // wait for all threads to finish processing existing information
+ usleep(1);
+ }
+ }
+
+ while (!server->shutdown()) usleep(1);
+ serverThread.join();
return 0;
}
diff --git a/libs/binder/tests/rpc_fuzzer/server.crt b/libs/binder/tests/rpc_fuzzer/server.crt
new file mode 100644
index 0000000..9142474
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/server.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICiTCCAXECFG1ggXE36l2WXeG6YTnaRVB7EmgQMA0GCSqGSIb3DQEBCwUAMAAw
+IBcNMjEwOTI5MDEzOTEzWhgPMjI5NTA3MTQwMTM5MTNaMAAwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDE3KnhPMwINpP5aIHIo/3GTlROZOK5AmkEsWmP
+w8smSWo2hJ7M0sOhruvOz82WORj48K8C0W72yFN+e9g32qoNMJFP/s6j1RWmaAKZ
+eSQUq6ixyaGhFLBOoukVykfTnY4qn4RbX5HzgpAPR1gv5ELvMXXPrxvtpIcVIrhm
+/dBQIa3iHZS6kypNbmRx/nhDVU8FK9s9WU5VLpbuNxv+m4X4Y1M/VZNatUMx5I0o
+ystV4JTqzjRZRPR4sxtMhu8/A11JsBVLeu8ZM/0IGCjmLOF4hy5a5YDv8MOJtdG2
+LI7ibZNtyrZiKwwhJc3tElzeIFit4T5Xjx69y/EMS4Hwhf3zAgMBAAEwDQYJKoZI
+hvcNAQELBQADggEBAD3gRbUybW7P2CihMyskTgS9HoIT9c02JWjtueWQIiQkyqTB
+6QdUQTHM5weil6TiW8NfpQQUIvrh66Pkph65shvFqxUsjdW25b4RbfUldFihfs1n
+kTa+e+hZONnVuzLvezIs2b8dygH9GA5y2OiLxwrMUcyaoCHGwKF7iOE0SJhfx0kY
+JDs4O+gAVjEsBSc24pm9aHBxgRCiEm1I4+RZf6PRBIz1ZadGBFsCZ+Gj6wyLP2Wq
+kjjMiV6o8pEjJjM+Oi4GfxvNewMCd2hMZYuJYpYC3cc7fPIpx8luidqKJdve8c6m
+KQ+dJ6ZQxEi0Zc9Jzre7NNoVcpIdc8SbkEM/DDo=
+-----END CERTIFICATE-----
diff --git a/libs/binder/tests/rpc_fuzzer/server.key b/libs/binder/tests/rpc_fuzzer/server.key
new file mode 100644
index 0000000..743470e
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAxNyp4TzMCDaT+WiByKP9xk5UTmTiuQJpBLFpj8PLJklqNoSe
+zNLDoa7rzs/NljkY+PCvAtFu9shTfnvYN9qqDTCRT/7Oo9UVpmgCmXkkFKuoscmh
+oRSwTqLpFcpH052OKp+EW1+R84KQD0dYL+RC7zF1z68b7aSHFSK4Zv3QUCGt4h2U
+upMqTW5kcf54Q1VPBSvbPVlOVS6W7jcb/puF+GNTP1WTWrVDMeSNKMrLVeCU6s40
+WUT0eLMbTIbvPwNdSbAVS3rvGTP9CBgo5izheIcuWuWA7/DDibXRtiyO4m2Tbcq2
+YisMISXN7RJc3iBYreE+V48evcvxDEuB8IX98wIDAQABAoIBACcI5jp+NqrOP6st
+uMZTFifzMi5VPMuYmcBPeXIDTc3qsr/ari5JAHeX2rQoakiGS9hYySsS4iDW+g9T
+eT0iA6QX5Ehrawf7YY6cgx9xcOEUZJ/ULlNlacw961/huzpPvHfhJ3qCycryMaSF
+7guZBFivgv/KZgxKGmrrdosdeufYXL3eHWZIrvcN4cDVgxslZg0o3Y5kCW3/KmDO
+QwvBlqgja93yImmkFA5BA/hQUsWuMBiR0xAd4b1NSBVCGTAYuCm6Up+6tIxeBSu5
+MVnNXbAIyVkbAS+gaR4uut6ObzFwUyGKDMaMpJ0LHLbusZy0svevu6Hjx+eH0ePC
+rj1xmDECgYEA4WR+1m3Tej0botG68+pZ8yLBgomSBAqpINCFkMEGQ2sQ1CqMMkHq
+8LAQNotU56W/0/H3eQemE3qBSKt1BUffpCvCHWkL9DRyDNhiq9U2PvV2Lx0Bv77e
+ET5MSDECUjlIsDqnv2qbq/m23BiP7AM8c9s6HjD0PqptyHjLlWHK86kCgYEA35hW
+AZEqMzsTNVQ8lXQtbqCyv8lls1SJbvIf3b5KItw9CwqpLr+UXssXh713j+yMW+WN
+3nv5+VaggkNBa9fHdqQEYT0L52OnLNjsfTlVhP5g2lOIa5VQYb/wqF1TaiZ27SGU
+lmLqiyArZgTnc3yo1wuIRPAbYbbm6CVnz7bm5jsCgYEAqfov7WZF5hnPjaq9YtWJ
+oGLFrLwy8flYMvcOw2vOXWmQ93Be6kfr9jfRAlFxZoEJeb0w9IVgKbBpb3Ree+0I
+K7cUXTmrWi9zE1zcjNnuXuyehElL2F8I+dgRjx/msDujJcQWXbT4UWmxDas4XrTS
+Ek1yNvKUP+4nfNgcMDvf4oECgYEAjgfYajpqEgzukKunqFAaI/HUWdt2zMlgW6dV
+8qdTtH0uEXt+KIHtn6FmmwURk8zxA9b3nWInUeljIBvUzMpOm+BoH9SFYUB+CxDo
+eEsZNdfYchcpyx0X6F/iYTCXMhCo7syr9DN1RVbz+mQXGdcP8ToUH6Zd3l4uozxP
+izRly80CgYEAqz7fCgQH74BwHoroSNdD3Cn6KNVx+oPuwRmzO4xMSOGyd/dNB2NA
+uzzuCTbrzC0jCXpqR0Bh9gYMjxyRZbifPX/YuFHyCIKK4+SQfeC4ZEwmSJVGWeh7
+3NksFJPCH4K3KbLNputByWJWOgKUdy70e/xOi83acBAVyRs+7H9LocE=
+-----END RSA PRIVATE KEY-----
diff --git a/libs/binder/tests/unit_fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
index b1263e8..8ea948c 100644
--- a/libs/binder/tests/unit_fuzzers/Android.bp
+++ b/libs/binder/tests/unit_fuzzers/Android.bp
@@ -30,16 +30,28 @@
"-Wall",
"-Werror",
],
- shared_libs: [
- "libbinder",
- "libutils",
- "libbase",
- ],
target: {
+ android: {
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libbase",
+ "libbinder",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libbase",
+ "libbinder",
+ ],
+ },
darwin: {
enabled: false,
- }
- }
+ },
+ },
}
cc_fuzz {
@@ -51,7 +63,6 @@
cc_fuzz {
name: "binder_bpBinderFuzz",
defaults: ["binder_fuzz_defaults"],
- host_supported: false,
srcs: ["BpBinderFuzz.cpp"],
}
diff --git a/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
index 69f1b9d..8d2b714 100644
--- a/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
@@ -72,6 +72,10 @@
},
[](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
bbinder->getDebugPid();
+ },
+ [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+ (void)bbinder->setRpcClientDebug(android::base::unique_fd(),
+ sp<BBinder>::make());
}};
} // namespace android
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index c50279b..e77c55c 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -19,8 +19,15 @@
#include <commonFuzzHelpers.h>
#include <fuzzer/FuzzedDataProvider.h>
+#include <android-base/logging.h>
#include <binder/BpBinder.h>
#include <binder/IServiceManager.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <thread>
namespace android {
@@ -28,13 +35,29 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp(data, size);
- // TODO: In the future it would be more effective to fork a new process and then pass a BBinder
- // to your process. Right now this is not implemented because it would involved fuzzing IPC on a
- // forked process, and libfuzzer will not be able to handle code coverage. This would lead to
- // crashes that are not easy to diagnose.
- int32_t handle = fdp.ConsumeIntegralInRange<int32_t>(0, 1024);
- sp<BpBinder> bpbinder = BpBinder::create(handle);
- if (bpbinder == nullptr) return 0;
+ std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
+ (void)unlink(addr.c_str());
+
+ sp<RpcServer> server = RpcServer::make();
+
+ // use RPC binder because fuzzer can't get coverage from another process.
+ auto thread = std::thread([&]() {
+ prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+ server->setRootObject(sp<BBinder>::make());
+ CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+ server->join();
+ });
+
+ sp<RpcSession> session = RpcSession::make();
+ status_t status;
+ for (size_t tries = 0; tries < 5; tries++) {
+ usleep(10000);
+ status = session->setupUnixDomainClient(addr.c_str());
+ if (status == OK) break;
+ }
+ CHECK_EQ(status, OK) << "Unable to connect";
+
+ sp<BpBinder> bpBinder = session->getRootObject()->remoteBinder();
// To prevent memory from running out from calling too many add item operations.
const uint32_t MAX_RUNS = 2048;
@@ -43,12 +66,16 @@
while (fdp.remaining_bytes() > 0 && count++ < MAX_RUNS) {
if (fdp.ConsumeBool()) {
- callArbitraryFunction(&fdp, gBPBinderOperations, bpbinder, s_recipient);
+ callArbitraryFunction(&fdp, gBPBinderOperations, bpBinder, s_recipient);
} else {
- callArbitraryFunction(&fdp, gIBinderOperations, bpbinder.get());
+ callArbitraryFunction(&fdp, gIBinderOperations, bpBinder.get());
}
}
+ CHECK(session->shutdownAndWait(true)) << "couldn't shutdown session";
+ CHECK(server->shutdown()) << "couldn't shutdown server";
+ thread.join();
+
return 0;
}
} // namespace android
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
index 6ca0e2f..5079431 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
@@ -30,7 +30,6 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
#include <stdio.h>
@@ -52,7 +51,7 @@
const sp<IBinder::DeathRecipient>& s_recipient) -> void {
// Clean up possible leftover memory.
wp<IBinder::DeathRecipient> outRecipient(nullptr);
- bpbinder->sendObituary();
+ if (!bpbinder->isRpcBinder()) bpbinder->sendObituary();
bpbinder->unlinkToDeath(nullptr, reinterpret_cast<void*>(&kBpBinderCookie), 0,
&outRecipient);
@@ -72,7 +71,9 @@
[](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
const sp<IBinder::DeathRecipient>&) -> void { bpbinder->remoteBinder(); },
[](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
- const sp<IBinder::DeathRecipient>&) -> void { bpbinder->sendObituary(); },
+ const sp<IBinder::DeathRecipient>&) -> void {
+ if (!bpbinder->isRpcBinder()) bpbinder->sendObituary();
+ },
[](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
const sp<IBinder::DeathRecipient>&) -> void {
uint32_t uid = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 626b758..bf7c613 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -27,7 +27,6 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/threads.h>
namespace android {
@@ -62,20 +61,22 @@
object = fdp->ConsumeIntegral<uint32_t>();
cleanup_cookie = fdp->ConsumeIntegral<uint32_t>();
IBinder::object_cleanup_func func = IBinder::object_cleanup_func();
- ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
- : nullptr,
- fdp->ConsumeBool() ? reinterpret_cast<void*>(&object) : nullptr,
- fdp->ConsumeBool() ? reinterpret_cast<void*>(&cleanup_cookie)
- : nullptr,
- func);
+ (void)ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
+ : nullptr,
+ fdp->ConsumeBool() ? reinterpret_cast<void*>(&object)
+ : nullptr,
+ fdp->ConsumeBool()
+ ? reinterpret_cast<void*>(&cleanup_cookie)
+ : nullptr,
+ func);
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t id = fdp->ConsumeIntegral<uint32_t>();
- ibinder->findObject(reinterpret_cast<void*>(&id));
+ (void)ibinder->findObject(reinterpret_cast<void*>(&id));
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t id = fdp->ConsumeIntegral<uint32_t>();
- ibinder->detachObject(reinterpret_cast<void*>(&id));
+ (void)ibinder->detachObject(reinterpret_cast<void*>(&id));
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t code = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp b/libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
index f9dda8c..f5e3af5 100644
--- a/libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
@@ -46,15 +46,6 @@
[&]() -> void { dealer->getAllocationAlignment(); },
[&]() -> void { dealer->getMemoryHeap(); },
[&]() -> void {
- size_t offset = fdp.ConsumeIntegral<size_t>();
-
- // Offset has already been freed, so return instead.
- if (free_list.find(offset) != free_list.end()) return;
-
- dealer->deallocate(offset);
- free_list.insert(offset);
- },
- [&]() -> void {
std::string randString = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
dealer->dump(randString.c_str());
},
diff --git a/libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
index 8b4ed70..371dcbd 100644
--- a/libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
@@ -31,37 +31,27 @@
static const std::vector<
std::function<void(FuzzedDataProvider*, android::sp<android::IBinder> const&)>>
gStabilityOperations = {
- // markCompilationUnit(IBinder* binder)
[](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
if (!marked) {
android::internal::Stability::markCompilationUnit(bbinder.get());
marked = true;
}
},
-
- // markVintf(IBinder* binder)
[](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
if (!marked) {
android::internal::Stability::markVintf(bbinder.get());
marked = true;
}
},
-
- // debugLogStability(const std::string& tag, const sp<IBinder>& binder)
- [](FuzzedDataProvider* fdp, android::sp<android::IBinder> const& bbinder) -> void {
- std::string tag = fdp->ConsumeRandomLengthString(STABILITY_MAX_TAG_LENGTH);
- android::internal::Stability::debugLogStability(tag, bbinder);
+ [](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
+ (void)android::internal::Stability::debugToString(bbinder);
},
-
- // markVndk(IBinder* binder)
[](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
if (!marked) {
android::internal::Stability::markVndk(bbinder.get());
marked = true;
}
},
-
- // requiresVintfDeclaration(const sp<IBinder>& binder)
[](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
android::internal::Stability::requiresVintfDeclaration(bbinder);
}};
diff --git a/libs/binderdebug/BinderDebug.cpp b/libs/binderdebug/BinderDebug.cpp
index b435dba..d086b49 100644
--- a/libs/binderdebug/BinderDebug.cpp
+++ b/libs/binderdebug/BinderDebug.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <binder/Binder.h>
@@ -116,4 +117,60 @@
return ret;
}
+status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
+ int32_t handle, std::vector<pid_t>* pids) {
+ std::smatch match;
+ static const std::regex kNodeNumber("^\\s+ref \\d+:\\s+desc\\s+(\\d+)\\s+node\\s+(\\d+).*");
+ std::string contextStr = contextToString(context);
+ int32_t node;
+ status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
+ if (std::regex_search(line, match, kNodeNumber)) {
+ const std::string& descString = match.str(1);
+ int32_t desc;
+ if (!::android::base::ParseInt(descString.c_str(), &desc)) {
+ LOG(ERROR) << "Failed to parse desc int: " << descString;
+ return;
+ }
+ if (handle != desc) {
+ return;
+ }
+ const std::string& nodeString = match.str(2);
+ if (!::android::base::ParseInt(nodeString.c_str(), &node)) {
+ LOG(ERROR) << "Failed to parse node int: " << nodeString;
+ return;
+ }
+ return;
+ }
+ return;
+ });
+ if (ret != OK) {
+ return ret;
+ }
+ static const std::regex kClients("^\\s+node\\s+(\\d+).*proc\\s+([\\d+\\s*]*)");
+ ret = scanBinderContext(servicePid, contextStr, [&](const std::string& line) {
+ if (std::regex_search(line, match, kClients)) {
+ const std::string nodeString = match.str(1);
+ int32_t matchedNode;
+ if (!::android::base::ParseInt(nodeString.c_str(), &matchedNode)) {
+ LOG(ERROR) << "Failed to parse node int: " << nodeString;
+ return;
+ }
+ if (node != matchedNode) {
+ return;
+ }
+ const std::string clients = match.str(2);
+ for (const std::string& pidStr : base::Split(clients, " ")) {
+ int32_t pid;
+ if (!::android::base::ParseInt(pidStr, &pid)) {
+ return;
+ }
+ pids->push_back(pid);
+ }
+ return;
+ }
+ return;
+ });
+ return ret;
+}
+
} // namespace android
diff --git a/libs/binderdebug/include/binderdebug/BinderDebug.h b/libs/binderdebug/include/binderdebug/BinderDebug.h
index 14a0ef3..dfd5a7c 100644
--- a/libs/binderdebug/include/binderdebug/BinderDebug.h
+++ b/libs/binderdebug/include/binderdebug/BinderDebug.h
@@ -32,6 +32,14 @@
VNDBINDER,
};
+/**
+ * pid is the pid of the service
+ */
status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
+/**
+ * pid is typically the pid of this process that is making the query
+ */
+status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
+ int32_t handle, std::vector<pid_t>* pids);
} // namespace android
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 570af71..79cc15f 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -12,12 +12,14 @@
srcs: ["cputimeinstate.cpp"],
shared_libs: [
"libbase",
- "libbpf",
- "libbpf_android",
+ "libbpf_bcc",
+ "libbpf_minimal",
"liblog",
- "libnetdutils"
],
- header_libs: ["bpf_prog_headers"],
+ header_libs: [
+ "bpf_prog_headers",
+ "bpf_headers",
+ ],
cflags: [
"-Werror",
"-Wall",
@@ -31,16 +33,19 @@
srcs: ["testtimeinstate.cpp"],
shared_libs: [
"libbase",
- "libbpf",
- "libbpf_android",
+ "libbpf_bcc",
+ "libbpf_minimal",
"libtimeinstate",
- "libnetdutils",
],
- header_libs: ["bpf_prog_headers"],
+ header_libs: [
+ "bpf_prog_headers",
+ "bpf_headers",
+ ],
cflags: [
"-Werror",
"-Wall",
"-Wextra",
],
require_root: true,
+ test_suites: ["general-tests"],
}
diff --git a/libs/cputimeinstate/TEST_MAPPING b/libs/cputimeinstate/TEST_MAPPING
new file mode 100644
index 0000000..4781520
--- /dev/null
+++ b/libs/cputimeinstate/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libtimeinstate_test"
+ }
+ ]
+}
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 2112b10..45a6d47 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -27,9 +27,11 @@
#include <gtest/gtest.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <cutils/android_filesystem_config.h>
#include <libbpf.h>
namespace android {
@@ -40,24 +42,31 @@
using std::vector;
-TEST(TimeInStateTest, IsTrackingSupported) {
- isTrackingUidTimesSupported();
- SUCCEED();
-}
+class TimeInStateTest : public testing::Test {
+ protected:
+ TimeInStateTest() {};
-TEST(TimeInStateTest, TotalTimeInState) {
+ void SetUp() {
+ if (!isTrackingUidTimesSupported() ||
+ !android::base::GetBoolProperty("sys.init.perf_lsm_hooks", false)) {
+ GTEST_SKIP();
+ }
+ }
+};
+
+TEST_F(TimeInStateTest, TotalTimeInState) {
auto times = getTotalCpuFreqTimes();
ASSERT_TRUE(times.has_value());
EXPECT_FALSE(times->empty());
}
-TEST(TimeInStateTest, SingleUidTimeInState) {
+TEST_F(TimeInStateTest, SingleUidTimeInState) {
auto times = getUidCpuFreqTimes(0);
ASSERT_TRUE(times.has_value());
EXPECT_FALSE(times->empty());
}
-TEST(TimeInStateTest, SingleUidConcurrentTimes) {
+TEST_F(TimeInStateTest, SingleUidConcurrentTimes) {
auto concurrentTimes = getUidConcurrentTimes(0);
ASSERT_TRUE(concurrentTimes.has_value());
ASSERT_FALSE(concurrentTimes->active.empty());
@@ -117,7 +126,7 @@
EXPECT_EQ(activeSum, policySum);
}
-TEST(TimeInStateTest, SingleUidTimesConsistent) {
+TEST_F(TimeInStateTest, SingleUidTimesConsistent) {
auto times = getUidCpuFreqTimes(0);
ASSERT_TRUE(times.has_value());
@@ -127,7 +136,7 @@
ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes));
}
-TEST(TimeInStateTest, AllUidTimeInState) {
+TEST_F(TimeInStateTest, AllUidTimeInState) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -163,7 +172,7 @@
ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC);
}
-TEST(TimeInStateTest, AllUidUpdatedTimeInState) {
+TEST_F(TimeInStateTest, AllUidUpdatedTimeInState) {
uint64_t lastUpdate = 0;
auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
ASSERT_TRUE(map1.has_value());
@@ -197,7 +206,7 @@
}
}
-TEST(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
+TEST_F(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
auto allUid = getUidsCpuFreqTimes();
auto total = getTotalCpuFreqTimes();
@@ -211,6 +220,7 @@
uint32_t totalFreqsCount = totalTimes.size();
std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
for (auto const &[uid, uidTimes]: *allUid) {
+ if (uid == AID_SDK_SANDBOX) continue;
for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
}
@@ -222,7 +232,7 @@
}
}
-TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
+TEST_F(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -246,7 +256,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimes) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimes) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &map : maps) {
@@ -264,7 +274,7 @@
}
}
-TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
+TEST_F(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
uint64_t lastUpdate = 0;
auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate);
ASSERT_TRUE(map1.has_value());
@@ -299,7 +309,7 @@
}
}
-TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+TEST_F(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &map : maps) {
@@ -328,7 +338,7 @@
ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
}
-TEST(TimeInStateTest, TotalTimeInStateMonotonic) {
+TEST_F(TimeInStateTest, TotalTimeInStateMonotonic) {
auto before = getTotalCpuFreqTimes();
ASSERT_TRUE(before.has_value());
sleep(1);
@@ -344,7 +354,7 @@
}
}
-TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
+TEST_F(TimeInStateTest, AllUidTimeInStateMonotonic) {
auto map1 = getUidsCpuFreqTimes();
ASSERT_TRUE(map1.has_value());
sleep(1);
@@ -365,7 +375,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
auto map1 = getUidsConcurrentTimes();
ASSERT_TRUE(map1.has_value());
ASSERT_FALSE(map1->empty());
@@ -393,7 +403,7 @@
}
}
-TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
+TEST_F(TimeInStateTest, AllUidTimeInStateSanityCheck) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -414,7 +424,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &concurrentMap : maps) {
@@ -441,7 +451,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
uint32_t uid = 0;
{
// Find an unused UID
@@ -463,7 +473,7 @@
ASSERT_FALSE(deleteMapEntry(fd, &key));
}
-TEST(TimeInStateTest, AllUidTimesConsistent) {
+TEST_F(TimeInStateTest, AllUidTimesConsistent) {
auto tisMap = getUidsCpuFreqTimes();
ASSERT_TRUE(tisMap.has_value());
@@ -481,7 +491,7 @@
}
}
-TEST(TimeInStateTest, RemoveUid) {
+TEST_F(TimeInStateTest, RemoveUid) {
uint32_t uid = 0;
{
// Find an unused UID
@@ -547,7 +557,7 @@
ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
}
-TEST(TimeInStateTest, GetCpuFreqs) {
+TEST_F(TimeInStateTest, GetCpuFreqs) {
auto freqs = getCpuFreqs();
ASSERT_TRUE(freqs.has_value());
@@ -583,7 +593,7 @@
return nullptr;
}
-TEST(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
+TEST_F(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
uint64_t startTimeNs = timeNanos();
sem_init(&pingsem, 0, 1);
@@ -638,5 +648,55 @@
}
}
+void *forceSwitchWithUid(void *uidPtr) {
+ if (!uidPtr) return nullptr;
+ setuid(*(uint32_t *)uidPtr);
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ return nullptr;
+}
+
+TEST_F(TimeInStateTest, SdkSandboxUid) {
+ // Find an unused app UID and its corresponding SDK sandbox uid.
+ uint32_t appUid = AID_APP_START, sandboxUid;
+ {
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) {
+ if (kv.first > AID_APP_END) break;
+ appUid = std::max(appUid, kv.first);
+ }
+ appUid++;
+ sandboxUid = appUid + (AID_SDK_SANDBOX_PROCESS_START - AID_APP_START);
+ }
+
+ // Create a thread to run with the fake sandbox uid.
+ pthread_t thread;
+ ASSERT_EQ(pthread_create(&thread, NULL, &forceSwitchWithUid, &sandboxUid), 0);
+ pthread_join(thread, NULL);
+
+ // Confirm we recorded stats for appUid and AID_SDK_SANDBOX but not sandboxUid
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_NE(allTimes->find(appUid), allTimes->end());
+ ASSERT_NE(allTimes->find(AID_SDK_SANDBOX), allTimes->end());
+ ASSERT_EQ(allTimes->find(sandboxUid), allTimes->end());
+
+ auto allConcurrentTimes = getUidsConcurrentTimes();
+ ASSERT_TRUE(allConcurrentTimes.has_value());
+ ASSERT_FALSE(allConcurrentTimes->empty());
+ ASSERT_NE(allConcurrentTimes->find(appUid), allConcurrentTimes->end());
+ ASSERT_NE(allConcurrentTimes->find(AID_SDK_SANDBOX), allConcurrentTimes->end());
+ ASSERT_EQ(allConcurrentTimes->find(sandboxUid), allConcurrentTimes->end());
+
+ ASSERT_TRUE(clearUidTimes(appUid));
+}
+
} // namespace bpf
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 761e45c..61e4a98 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -78,4 +78,20 @@
return std::nullopt;
}
+std::optional<IServiceManager::ConnectionInfo> ServiceManager::getConnectionInfo(
+ const String16& name) {
+ (void)name;
+ return std::nullopt;
+}
+
+status_t ServiceManager::registerForNotifications(const String16&,
+ const sp<LocalRegistrationCallback>&) {
+ return INVALID_OPERATION;
+}
+
+status_t ServiceManager::unregisterForNotifications(const String16&,
+ const sp<LocalRegistrationCallback>&) {
+ return INVALID_OPERATION;
+}
+
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index e26c21b..6d6e008 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -51,6 +51,13 @@
std::optional<String16> updatableViaApex(const String16& name) override;
+ std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+
+ status_t registerForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) override;
+
+ status_t unregisterForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) override;
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
index 93879d8..72ff978 100644
--- a/libs/gralloc/OWNERS
+++ b/libs/gralloc/OWNERS
@@ -1 +1,4 @@
+# Graphics team
+alecmouri@google.com
chrisforbes@google.com
+jreck@google.com
\ No newline at end of file
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index a0032ae..9a7bad4 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -23,7 +23,6 @@
cc_library {
name: "libgralloctypes",
- defaults: ["libbinder_ndk_host_user"],
cflags: [
"-Wall",
"-Werror",
@@ -33,7 +32,7 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
vendor_available: true,
@@ -48,18 +47,18 @@
min_sdk_version: "29",
srcs: [
- "Gralloc4.cpp"
+ "Gralloc4.cpp",
],
shared_libs: [
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index e2f072a..81a529d 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -196,6 +196,35 @@
status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedMetadataType);
/**
+ * Private helper functions
+ */
+template <class T>
+status_t encodeInteger(const T& input, OutputHidlVec* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
+ return output->encode(tmp, sizeof(input));
+}
+
+template <class T>
+status_t decodeInteger(InputHidlVec* input, T* output) {
+ static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
+ return input->decode(tmp, sizeof(*output));
+}
+
+/**
* encode/encodeMetadata are the main encoding functions. They take in T and uses the encodeHelper
* function to turn T into the hidl_vec byte stream.
*
@@ -251,10 +280,45 @@
template <class T>
status_t encodeOptionalMetadata(const MetadataType& metadataType, const std::optional<T>& input,
hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
- if (!input) {
- return NO_ERROR;
+ OutputHidlVec outputHidlVec{output};
+
+ status_t err = encodeMetadataType(metadataType, &outputHidlVec);
+ if (err) {
+ return err;
}
- return encodeMetadata(metadataType, *input, output, encodeHelper);
+
+ err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ if (input) {
+ err = encodeHelper(*input, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+ }
+
+ err = outputHidlVec.resize();
+ if (err) {
+ return err;
+ }
+
+ err = encodeMetadataType(metadataType, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ err = encodeInteger<uint32_t>(input.has_value() ? 1 : 0, &outputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ if (input) {
+ return encodeHelper(*input, &outputHidlVec);
+ }
+
+ return NO_ERROR;
}
/**
@@ -315,45 +379,36 @@
if (!output) {
return BAD_VALUE;
}
- if (input.size() <= 0) {
- output->reset();
- return NO_ERROR;
+
+ InputHidlVec inputHidlVec{&input};
+
+ status_t err = validateMetadataType(&inputHidlVec, metadataType);
+ if (err) {
+ return err;
}
- T tmp;
- status_t err = decodeMetadata(metadataType, input, &tmp, decodeHelper);
- if (!err) {
+
+ uint32_t present = 0;
+ err = decodeInteger<uint32_t>(&inputHidlVec, &present);
+ if (err) {
+ return err;
+ }
+
+ if (present) {
+ T tmp;
+ err = decodeHelper(&inputHidlVec, &tmp);
+ if (err) {
+ return err;
+ }
+
*output = tmp;
}
- return err;
-}
-/**
- * Private helper functions
- */
-template <class T>
-status_t encodeInteger(const T& input, OutputHidlVec* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
+ err = inputHidlVec.hasRemainingData();
+ if (err) {
return BAD_VALUE;
}
- const uint8_t* tmp = reinterpret_cast<const uint8_t*>(&input);
- return output->encode(tmp, sizeof(input));
-}
-
-template <class T>
-status_t decodeInteger(InputHidlVec* input, T* output) {
- static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
- std::is_same<T, float>::value || std::is_same<T, double>::value);
- if (!output) {
- return BAD_VALUE;
- }
-
- uint8_t* tmp = reinterpret_cast<uint8_t*>(output);
- return input->decode(tmp, sizeof(*output));
+ return NO_ERROR;
}
status_t encodeString(const std::string& input, OutputHidlVec* output) {
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 6689771..3c3b6af 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -9,12 +9,11 @@
cc_fuzz {
name: "libgralloctypes_fuzzer",
- defaults: ["libbinder_ndk_host_user"],
host_supported: true,
target: {
darwin: {
enabled: false,
- }
+ },
},
fuzz_config: {
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index f2d0943..858739c 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -88,6 +88,7 @@
if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status;
if ((status = parcel->writeBool(falsePrerotation)) != OK) return status;
if ((status = parcel->writeBool(gles1InUse)) != OK) return status;
+ if ((status = parcel->writeBool(angleInUse)) != OK) return status;
return OK;
}
@@ -101,6 +102,7 @@
if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status;
if ((status = parcel->readBool(&falsePrerotation)) != OK) return status;
if ((status = parcel->readBool(&gles1InUse)) != OK) return status;
+ if ((status = parcel->readBool(&angleInUse)) != OK) return status;
return OK;
}
@@ -111,6 +113,7 @@
StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse);
StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation);
StringAppendF(&result, "gles1InUse = %d\n", gles1InUse);
+ StringAppendF(&result, "angleInUse = %d\n", angleInUse);
result.append("glDriverLoadingTime:");
for (int32_t loadingTime : glDriverLoadingTime) {
StringAppendF(&result, " %d", loadingTime);
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index 9aba69f..5b513d2 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -16,6 +16,7 @@
#pragma once
+#include <chrono>
#include <string>
#include <vector>
@@ -52,7 +53,7 @@
};
/*
- * class for transporting gpu app stats from GpuService to authorized recipents.
+ * class for transporting gpu app stats from GpuService to authorized recipients.
* This class is intended to be a data container.
*/
class GpuStatsAppInfo : public Parcelable {
@@ -72,6 +73,9 @@
bool cpuVulkanInUse = false;
bool falsePrerotation = false;
bool gles1InUse = false;
+ bool angleInUse = false;
+
+ std::chrono::time_point<std::chrono::system_clock> lastAccessTime;
};
/*
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 8c250a4..bd9abc1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -136,8 +136,8 @@
],
aidl: {
- export_aidl_headers: true
- }
+ export_aidl_headers: true,
+ },
}
cc_library_shared {
@@ -206,7 +206,6 @@
],
shared_libs: [
- "android.frameworks.bufferhub@1.0",
"libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
@@ -232,7 +231,6 @@
"BufferHubProducer.cpp",
],
exclude_shared_libs: [
- "android.frameworks.bufferhub@1.0",
"libbufferhub",
"libbufferhubqueue",
"libpdx_default_transport",
@@ -250,10 +248,7 @@
"libpdx_headers",
],
- pgo: {
- sampling: true,
- profile_file: "libgui/libgui.profdata",
- },
+ afdo: true,
lto: {
thin: true,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index df308d8..5fe5e71 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -645,7 +645,10 @@
slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
return BAD_VALUE;
} else if (!mSlots[slot].mBufferState.isDequeued()) {
- BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
+ // TODO(http://b/140581935): This message is BQ_LOGW because it
+ // often logs when no actionable errors are present. Return to
+ // using BQ_LOGE after ensuring this only logs during errors.
+ BQ_LOGW("detachBuffer: slot %d is not owned by the producer "
"(state = %s)", slot, mSlots[slot].mBufferState.string());
return BAD_VALUE;
} else if (!mSlots[slot].mRequestBufferCalled) {
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 8edf604..a626970 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -71,6 +71,7 @@
case HAL_PIXEL_FORMAT_Y8:
case HAL_PIXEL_FORMAT_Y16:
case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW12:
case HAL_PIXEL_FORMAT_RAW10:
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
case HAL_PIXEL_FORMAT_BLOB:
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index e1b1efc..46800f2 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -33,10 +33,13 @@
// using just a few large reads.
static const size_t EVENT_BUFFER_SIZE = 100;
+static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
+
DisplayEventDispatcher::DisplayEventDispatcher(
const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::EventRegistrationFlags eventRegistration)
- : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
+ : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
+ mLastVsyncCount(0), mLastScheduleVsyncTime(0) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -86,6 +89,7 @@
}
mWaitingForVsync = true;
+ mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
}
return OK;
}
@@ -124,9 +128,21 @@
this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
vsyncEventData.id);
mWaitingForVsync = false;
+ mLastVsyncCount = vsyncCount;
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
}
+ if (mWaitingForVsync) {
+ const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
+ if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
+ ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
+ mWaitingForVsync = false;
+ dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
+ ++mLastVsyncCount, vsyncEventData /* empty data */);
+ }
+ }
+
return 1; // keep the callback
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 30d19e3..b3647d6 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -301,7 +301,7 @@
// continues to use it.
sp<GraphicBuffer> buffer = new GraphicBuffer(
kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
"[GLConsumer debug texture]");
uint32_t* bits;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 4ade240..08f3597 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -56,6 +56,8 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
+ uint32_t mLastVsyncCount;
+ nsecs_t mLastScheduleVsyncTime;
std::vector<FrameRateOverride> mFrameRateOverrides;
diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h
index b9ec14a..e5d2684 100644
--- a/libs/gui/include/gui/TraceUtils.h
+++ b/libs/gui/include/gui/TraceUtils.h
@@ -16,6 +16,8 @@
#pragma once
+#include <stdarg.h>
+
#include <cutils/trace.h>
#include <utils/Trace.h>
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index e73c3b8..71a1291 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -113,7 +113,7 @@
"frameworks/native/libs/arect/include",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"InputTransport.cpp",
"android/os/IInputConstants.aidl",
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 220c8e1..1aec477 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -89,8 +89,15 @@
// Treblized input device config files will be located /product/usr, /system_ext/usr,
// /odm/usr or /vendor/usr.
- const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
- getenv("ANDROID_ROOT")};
+ // These files may also be in the com.android.input.config APEX.
+ const char* rootsForPartition[]{
+ "/product",
+ "/system_ext",
+ "/odm",
+ "/vendor",
+ "/apex/com.android.input.config/etc",
+ getenv("ANDROID_ROOT"),
+ };
for (size_t i = 0; i < size(rootsForPartition); i++) {
if (rootsForPartition[i] == nullptr) {
continue;
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index 2c04d42..6e991e9 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -18,7 +18,7 @@
//#define LOG_NDEBUG 0
// Log debug messages about acceleration.
-#define DEBUG_ACCELERATION 0
+static constexpr bool DEBUG_ACCELERATION = false;
#include <math.h>
#include <limits.h>
@@ -52,10 +52,10 @@
void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
if (eventTime >= mLastMovementTime + STOP_TIME) {
-#if DEBUG_ACCELERATION
- ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
- (eventTime - mLastMovementTime) * 0.000001f);
-#endif
+ if (DEBUG_ACCELERATION && mLastMovementTime != LLONG_MIN) {
+ ALOGD("VelocityControl: stopped, last movement was %0.3fms ago",
+ (eventTime - mLastMovementTime) * 0.000001f);
+ }
reset();
}
@@ -83,19 +83,20 @@
* (mParameters.acceleration - 1);
}
-#if DEBUG_ACCELERATION
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
- "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration,
- vx, vy, speed, scale / mParameters.scale);
-#endif
+ if (DEBUG_ACCELERATION) {
+ ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
+ "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration,
+ vx, vy, speed, scale / mParameters.scale);
+ }
+
} else {
-#if DEBUG_ACCELERATION
- ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration);
-#endif
+ if (DEBUG_ACCELERATION) {
+ ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration);
+ }
}
if (deltaX) {
diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 2f31888..0128859 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -191,7 +191,7 @@
// continues to use it.
sp<GraphicBuffer> buffer =
new GraphicBuffer(kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
"[EGLConsumer debug texture]");
uint32_t* bits;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
@@ -593,6 +593,10 @@
}
void EGLConsumer::onFreeBufferLocked(int slotIndex) {
+ if (mEglSlots[slotIndex].mEglImage != nullptr &&
+ mEglSlots[slotIndex].mEglImage == mCurrentTextureImage) {
+ mCurrentTextureImage.clear();
+ }
mEglSlots[slotIndex].mEglImage.clear();
}
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 79b47a1..af55623 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -207,7 +207,11 @@
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- outPlanes->planes[0].pixelStride = 1;
+ if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010) {
+ outPlanes->planes[0].pixelStride = 2;
+ } else {
+ outPlanes->planes[0].pixelStride = 1;
+ }
outPlanes->planes[0].rowStride = yuvData.ystride;
outPlanes->planes[1].data = yuvData.cb;
outPlanes->planes[1].pixelStride = yuvData.chroma_step;
@@ -588,6 +592,8 @@
"HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
"HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010,
+ "HAL and AHardwareBuffer pixel format don't match");
switch (format) {
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
@@ -617,6 +623,7 @@
case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
return true;
default:
@@ -633,6 +640,7 @@
case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
return true;
default:
return false;
@@ -653,6 +661,8 @@
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
return 4;
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ return 8;
default:
return 0;
}
@@ -696,6 +706,10 @@
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
"gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_CAMERA_WRITE == (uint64_t)BufferUsage::CAMERA_OUTPUT,
+ "gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_CAMERA_READ == (uint64_t)BufferUsage::CAMERA_INPUT,
+ "gralloc and AHardwareBuffer flags don't match");
return usage;
}
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index d93a84c..78c56d9 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -158,6 +158,14 @@
* cube-maps or multi-layered textures.
*/
AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23,
+
+ /**
+ * YUV P010 format.
+ * Must have an even width and height. Can be accessed in OpenGL
+ * shaders through an external sampler. Does not support mip-maps
+ * cube-maps or multi-layered textures.
+ */
+ AHARDWAREBUFFER_FORMAT_YCbCr_P010 = 0x36,
};
/**
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 50fe0b7..21931bb 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -91,6 +91,20 @@
AHARDWAREBUFFER_FORMAT_YCbCr_422_I = 0x14,
};
+/**
+ * Buffer usage flags.
+ */
+enum {
+ /* for future proofing, keep these in sync with hardware/gralloc.h */
+
+ /* The buffer will be written by the HW camera pipeline. */
+ AHARDWAREBUFFER_USAGE_CAMERA_WRITE = 2UL << 16,
+ /* The buffer will be read by the HW camera pipeline. */
+ AHARDWAREBUFFER_USAGE_CAMERA_READ = 4UL << 16,
+ /* Mask for the camera access values. */
+ AHARDWAREBUFFER_USAGE_CAMERA_MASK = 6UL << 16,
+};
+
__END_DECLS
#endif /* ANDROID_VNDK_NATIVEWINDOW_AHARDWAREBUFFER_H */
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index e3d705f..abcd527 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -147,7 +147,8 @@
OP_ACTIVITY_RECOGNITION_SOURCE = 113,
OP_BLUETOOTH_ADVERTISE = 114,
OP_RECORD_INCOMING_PHONE_AUDIO = 115,
- _NUM_OP = 116
+ OP_NEARBY_WIFI_DEVICES = 116,
+ _NUM_OP = 117
};
AppOpsManager();
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index c478506..5d23a5e 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,4 @@
+adyabr@google.com
alecmouri@google.com
djsollen@google.com
jreck@google.com
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 0c5a851..9e466b6 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -26,55 +26,39 @@
namespace android {
namespace renderengine {
-std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
- RenderEngineType renderEngineType = args.renderEngineType;
-
+std::unique_ptr<RenderEngine> RenderEngine::create(RenderEngineCreationArgs args) {
// Keep the ability to override by PROPERTIES:
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
if (strcmp(prop, "gles") == 0) {
- renderEngineType = RenderEngineType::GLES;
+ args.renderEngineType = RenderEngineType::GLES;
}
if (strcmp(prop, "threaded") == 0) {
- renderEngineType = RenderEngineType::THREADED;
+ args.renderEngineType = RenderEngineType::THREADED;
}
if (strcmp(prop, "skiagl") == 0) {
- renderEngineType = RenderEngineType::SKIA_GL;
+ args.renderEngineType = RenderEngineType::SKIA_GL;
}
if (strcmp(prop, "skiaglthreaded") == 0) {
- renderEngineType = RenderEngineType::SKIA_GL_THREADED;
+ args.renderEngineType = RenderEngineType::SKIA_GL_THREADED;
}
- switch (renderEngineType) {
+ switch (args.renderEngineType) {
case RenderEngineType::THREADED:
ALOGD("Threaded RenderEngine with GLES Backend");
return renderengine::threaded::RenderEngineThreaded::create(
[args]() { return android::renderengine::gl::GLESRenderEngine::create(args); },
- renderEngineType);
+ args.renderEngineType);
case RenderEngineType::SKIA_GL:
ALOGD("RenderEngine with SkiaGL Backend");
return renderengine::skia::SkiaGLRenderEngine::create(args);
case RenderEngineType::SKIA_GL_THREADED: {
- // These need to be recreated, since they are a constant reference, and we need to
- // let SkiaRE know that it's running as threaded, and all GL operation will happen on
- // the same thread.
- RenderEngineCreationArgs skiaArgs =
- RenderEngineCreationArgs::Builder()
- .setPixelFormat(args.pixelFormat)
- .setImageCacheSize(args.imageCacheSize)
- .setUseColorManagerment(args.useColorManagement)
- .setEnableProtectedContext(args.enableProtectedContext)
- .setPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly)
- .setSupportsBackgroundBlur(args.supportsBackgroundBlur)
- .setContextPriority(args.contextPriority)
- .setRenderEngineType(renderEngineType)
- .build();
ALOGD("Threaded RenderEngine with SkiaGL Backend");
return renderengine::threaded::RenderEngineThreaded::create(
- [skiaArgs]() {
- return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs);
+ [args]() {
+ return android::renderengine::skia::SkiaGLRenderEngine::create(args);
},
- renderEngineType);
+ args.renderEngineType);
}
case RenderEngineType::GLES:
default:
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 967cf5d..f555cdb 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -98,7 +98,7 @@
SKIA_GL_THREADED = 4,
};
- static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
+ static std::unique_ptr<RenderEngine> create(RenderEngineCreationArgs args);
virtual ~RenderEngine() = 0;
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index ae8f238..cc627b8 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -388,7 +388,10 @@
drawBlurLayers(renderengine, display, dstTexture);
}
- // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+ // The majority of skia shaders needed by RenderEngine are related to sampling images.
+ // These need to be generated with various source textures.
+ // Make a list of applicable sources.
+ // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
sp<GraphicBuffer> externalBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
@@ -396,24 +399,24 @@
const auto externalTexture =
std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
ExternalTexture::Usage::READABLE);
+ std::vector<const std::shared_ptr<ExternalTexture>> textures =
+ {srcTexture, externalTexture};
- // Another external texture with a different pixel format triggers useIsOpaqueWorkaround
+ // Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
+ // It doesn't have to be f16, but it can't be the usual 8888.
sp<GraphicBuffer> f16ExternalBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16,
1, usageExternal, "primeShaderCache_external_f16");
- const auto f16ExternalTexture =
+ // The F16 texture may not be usable on all devices, so check first that it was created.
+ status_t error = f16ExternalBuffer->initCheck();
+ if (!error) {
+ const auto f16ExternalTexture =
std::make_shared<ExternalTexture>(f16ExternalBuffer, *renderengine,
ExternalTexture::Usage::READABLE);
+ textures.push_back(f16ExternalTexture);
+ }
- // The majority of shaders are related to sampling images.
- // These need to be generated with various source textures
- // The F16 texture may not be usable on all devices, so check first that it was created with
- // the requested usage bit.
- auto textures = {srcTexture, externalTexture};
- auto texturesWithF16 = {srcTexture, externalTexture, f16ExternalTexture};
- bool canUsef16 = f16ExternalBuffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE;
-
- for (auto texture : canUsef16 ? texturesWithF16 : textures) {
+ for (auto texture : textures) {
drawImageLayers(renderengine, display, dstTexture, texture);
// Draw layers for b/185569240.
drawClippedLayers(renderengine, display, dstTexture, texture);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 74d17ce..506e308 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -54,7 +54,7 @@
target: {
windows: {
enabled: true,
- }
+ },
},
defaults: [
@@ -159,7 +159,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -176,7 +176,7 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
@@ -225,6 +225,8 @@
"libui_headers",
],
min_sdk_version: "29",
+
+ afdo: true,
}
cc_library_headers {
@@ -266,6 +268,6 @@
"Rect.cpp",
"Region.cpp",
"PixelFormat.cpp",
- "Transform.cpp"
+ "Transform.cpp",
],
}
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 80f6c82..162fd95 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -300,20 +300,19 @@
if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
continue;
}
- if (0 != planeLayoutComponent.offsetInBits % 8) {
- unlock(bufferHandle);
- return BAD_VALUE;
- }
- uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes +
- (planeLayoutComponent.offsetInBits / 8);
+ uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
+
+ // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
+ // but we still want to point to the start of the first byte.
+ tmpData += (planeLayoutComponent.offsetInBits / 8);
+
uint64_t sampleIncrementInBytes;
auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
switch (type) {
case PlaneLayoutComponentType::Y:
- if ((ycbcr.y != nullptr) || (planeLayoutComponent.sizeInBits != 8) ||
- (planeLayout.sampleIncrementInBits != 8)) {
+ if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
unlock(bufferHandle);
return BAD_VALUE;
}
@@ -329,7 +328,8 @@
}
sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
- if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2)) {
+ if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
+ (sampleIncrementInBytes != 4)) {
unlock(bufferHandle);
return BAD_VALUE;
}
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
index 0997e9f..d073e2b 100644
--- a/libs/vibrator/OWNERS
+++ b/libs/vibrator/OWNERS
@@ -1,2 +1 @@
-lsandrade@google.com
-michaelwr@google.com
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index a8a8476..de7d8f8 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -17,6 +17,7 @@
#include <processgroup/sched_policy.h>
#include <sys/prctl.h>
#include <sys/resource.h>
+#include <utils/ThreadDefs.h>
#include <functional>
diff --git a/opengl/OWNERS b/opengl/OWNERS
index a9bd4bb..a47fb9a 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -1,6 +1,12 @@
+abdolrashidi@google.com
+cclao@google.com
chrisforbes@google.com
cnorthrop@google.com
ianelliott@google.com
jessehall@google.com
+lfy@google.com
lpy@google.com
timvp@google.com
+romanl@google.com
+vantablack@google.com
+yuxinhu@google.com
diff --git a/opengl/libs/EGL/GLES_layers.md b/opengl/libs/EGL/GLES_layers.md
index bfc44db..f6a8f14 100644
--- a/opengl/libs/EGL/GLES_layers.md
+++ b/opengl/libs/EGL/GLES_layers.md
@@ -251,7 +251,7 @@
- Secondly, if you want to determine from an application that can't call out to ADB for this, you can check for the [EGL_ANDROID_GLES_layers](../../specs/EGL_ANDROID_GLES_layers.txt). It simply indicates support of this layering system:
```cpp
std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
- if (display_extension.find("EGL_ANDROID_GLES_layers") != std::string::npos)
+ if (display_extensions.find("EGL_ANDROID_GLES_layers") != std::string::npos)
{
// Layers are supported!
}
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index e6fb2c3..d11631b 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -7,7 +7,7 @@
default_applicable_licenses: ["frameworks_native_license"],
}
-cc_library_shared {
+cc_library {
name: "libaudiomanager",
srcs: [
diff --git a/services/batteryservice/include/batteryservice/BatteryService.h b/services/batteryservice/include/batteryservice/BatteryService.h
index 1e8eb1e..178bc29 100644
--- a/services/batteryservice/include/batteryservice/BatteryService.h
+++ b/services/batteryservice/include/batteryservice/BatteryService.h
@@ -40,6 +40,7 @@
bool chargerAcOnline;
bool chargerUsbOnline;
bool chargerWirelessOnline;
+ bool chargerDockOnline;
int maxChargingCurrent;
int maxChargingVoltage;
int batteryStatus;
diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS
index ac300d0..0ff65bf 100644
--- a/services/gpuservice/OWNERS
+++ b/services/gpuservice/OWNERS
@@ -1,2 +1,6 @@
chrisforbes@google.com
lpy@google.com
+alecmouri@google.com
+lfy@google.com
+paulthomson@google.com
+pbaiget@google.com
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index 9842ed7..076affd 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -24,6 +24,7 @@
bpf {
name: "gpu_mem.o",
srcs: ["gpu_mem.c"],
+ btf: true,
cflags: [
"-Wall",
"-Werror",
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
index 830e53d..d0ea856 100644
--- a/services/gpuservice/gpumem/Android.bp
+++ b/services/gpuservice/gpumem/Android.bp
@@ -26,19 +26,17 @@
srcs: [
"GpuMem.cpp",
],
+ header_libs: ["bpf_headers"],
shared_libs: [
"libbase",
- "libbpf",
- "libbpf_android",
+ "libbpf_bcc",
"libcutils",
"liblog",
"libutils",
],
export_include_dirs: ["include"],
- export_shared_lib_headers: [
- "libbase",
- "libbpf_android",
- ],
+ export_header_lib_headers: ["bpf_headers"],
+ export_shared_lib_headers: ["libbase"],
cppflags: [
"-Wall",
"-Werror",
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index 3aa862f..dd3cc3b 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -22,7 +22,7 @@
#include <android-base/stringprintf.h>
#include <libbpf.h>
-#include <libbpf_android.h>
+#include <bpf/WaitForProgsLoaded.h>
#include <log/log.h>
#include <unistd.h>
#include <utils/Timers.h>
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 220952d..d033453 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -84,6 +84,38 @@
}
}
+void GpuStats::purgeOldDriverStats() {
+ ALOG_ASSERT(mAppStats.size() == MAX_NUM_APP_RECORDS);
+
+ struct GpuStatsApp {
+ // Key is <app package name>+<driver version code>.
+ const std::string *appStatsKey = nullptr;
+ const std::chrono::time_point<std::chrono::system_clock> *lastAccessTime = nullptr;
+ };
+ std::vector<GpuStatsApp> gpuStatsApps(MAX_NUM_APP_RECORDS);
+
+ // Create a list of pointers to package names and their last access times.
+ int index = 0;
+ for (const auto & [appStatsKey, gpuStatsAppInfo] : mAppStats) {
+ GpuStatsApp &gpuStatsApp = gpuStatsApps[index];
+ gpuStatsApp.appStatsKey = &appStatsKey;
+ gpuStatsApp.lastAccessTime = &gpuStatsAppInfo.lastAccessTime;
+ ++index;
+ }
+
+ // Sort the list with the oldest access times at the front.
+ std::sort(gpuStatsApps.begin(), gpuStatsApps.end(), [](GpuStatsApp a, GpuStatsApp b) -> bool {
+ return *a.lastAccessTime < *b.lastAccessTime;
+ });
+
+ // Remove the oldest packages from mAppStats to make room for new apps.
+ for (int i = 0; i < APP_RECORD_HEADROOM; ++i) {
+ mAppStats.erase(*gpuStatsApps[i].appStatsKey);
+ gpuStatsApps[i].appStatsKey = nullptr;
+ gpuStatsApps[i].lastAccessTime = nullptr;
+ }
+}
+
void GpuStats::insertDriverStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
@@ -123,19 +155,22 @@
const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
if (!mAppStats.count(appStatsKey)) {
if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
- ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
- return;
+ ALOGV("GpuStatsAppInfo has reached maximum size. Removing old stats to make room.");
+ purgeOldDriverStats();
}
GpuStatsAppInfo appInfo;
addLoadingTime(driver, driverLoadingTime, &appInfo);
appInfo.appPackageName = appPackageName;
appInfo.driverVersionCode = driverVersionCode;
+ appInfo.angleInUse = driverPackageName == "angle";
+ appInfo.lastAccessTime = std::chrono::system_clock::now();
mAppStats.insert({appStatsKey, appInfo});
- return;
+ } else {
+ mAppStats[appStatsKey].angleInUse = driverPackageName == "angle";
+ addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
+ mAppStats[appStatsKey].lastAccessTime = std::chrono::system_clock::now();
}
-
- addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
}
void GpuStats::insertTargetStats(const std::string& appPackageName,
@@ -311,7 +346,8 @@
angleDriverBytes.length()),
ele.second.cpuVulkanInUse,
ele.second.falsePrerotation,
- ele.second.gles1InUse);
+ ele.second.gles1InUse,
+ ele.second.angleInUse);
}
}
diff --git a/services/gpuservice/gpustats/include/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
index 55f0da1..2aba651 100644
--- a/services/gpuservice/gpustats/include/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
@@ -46,6 +46,11 @@
// This limits the worst case number of loading times tracked.
static const size_t MAX_NUM_LOADING_TIMES = 50;
+ // Below limits the memory usage of GpuStats to be less than 10KB. This is
+ // the preferred number for statsd while maintaining nice data quality.
+ static const size_t MAX_NUM_APP_RECORDS = 100;
+ // The number of apps to remove when mAppStats fills up.
+ static const size_t APP_RECORD_HEADROOM = 10;
private:
// Friend class for testing.
@@ -55,6 +60,10 @@
static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag,
AStatsEventList* data,
void* cookie);
+
+ // Remove old packages from mAppStats.
+ void purgeOldDriverStats();
+
// Pull global into into global atom.
AStatsManager_PullAtomCallbackReturn pullGlobalInfoAtom(AStatsEventList* data);
// Pull app into into app atom.
@@ -68,9 +77,6 @@
// Registers statsd callbacks if they have not already been registered
void registerStatsdCallbacksIfNeeded();
- // Below limits the memory usage of GpuStats to be less than 10KB. This is
- // the preferred number for statsd while maintaining nice data quality.
- static const size_t MAX_NUM_APP_RECORDS = 100;
// GpuStats access should be guarded by mLock.
std::mutex mLock;
// True if statsd callbacks have been registered.
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 6d87c45..4fb0d2e 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -32,10 +32,10 @@
"GpuMemTracerTest.cpp",
"GpuStatsTest.cpp",
],
+ header_libs: ["bpf_headers"],
shared_libs: [
"libbase",
- "libbpf",
- "libbpf_android",
+ "libbpf_bcc",
"libcutils",
"libgfxstats",
"libgpumem",
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 37ebeae..20c8ccf 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "gpuservice_unittest"
+#include <unistd.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
#include <gpustats/GpuStats.h>
@@ -221,6 +222,51 @@
EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
}
+// Verify we always have the most recently used apps in mAppStats, even when we fill it.
+TEST_F(GpuStatsTest, canInsertMoreThanMaxNumAppRecords) {
+ constexpr int kNumExtraApps = 15;
+ static_assert(kNumExtraApps > GpuStats::APP_RECORD_HEADROOM);
+
+ // Insert stats for GpuStats::MAX_NUM_APP_RECORDS so we fill it up.
+ for (int i = 0; i < GpuStats::MAX_NUM_APP_RECORDS + kNumExtraApps; ++i) {
+ std::stringstream nameStream;
+ nameStream << "testapp" << "_" << i;
+ std::string fullPkgName = nameStream.str();
+
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME,
+ fullPkgName, VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+ mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+ mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+ mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(fullPkgName.c_str()));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("cpuVulkanInUse = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("falsePrerotation = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
+ }
+
+ // mAppStats purges GpuStats::APP_RECORD_HEADROOM apps removed everytime it's filled up.
+ int numPurges = kNumExtraApps / GpuStats::APP_RECORD_HEADROOM;
+ numPurges += (kNumExtraApps % GpuStats::APP_RECORD_HEADROOM) == 0 ? 0 : 1;
+
+ // Verify the remaining apps are present.
+ for (int i = numPurges * GpuStats::APP_RECORD_HEADROOM;
+ i < GpuStats::MAX_NUM_APP_RECORDS + kNumExtraApps;
+ ++i) {
+ std::stringstream nameStream;
+ // Add a newline to search for the exact package name.
+ nameStream << "testapp" << "_" << i << "\n";
+ std::string fullPkgName = nameStream.str();
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(fullPkgName.c_str()));
+ }
+}
+
TEST_F(GpuStatsTest, canDumpAllBeforeClearAll) {
mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS
new file mode 100644
index 0000000..e789052
--- /dev/null
+++ b/services/gpuservice/vts/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 653544
+paulthomson@google.com
+pbaiget@google.com
+lfy@google.com
+chrisforbes@google.com
+lpy@google.com
+alecmouri@google.com
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 464236d..d53495f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1268,6 +1268,11 @@
entry.deviceId);
#endif
+ // Reset key repeating in case a keyboard device was disabled or enabled.
+ if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->deviceId == entry.deviceId) {
+ resetKeyRepeatLocked();
+ }
+
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset");
options.deviceId = entry.deviceId;
synthesizeCancelationEventsForAllConnectionsLocked(options);
@@ -3940,6 +3945,13 @@
args->downTime, args->pointerCount,
args->pointerProperties, args->pointerCoords, 0, 0);
+ if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
+ IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
+ !mInputFilterEnabled) {
+ const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
+ mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
+ }
+
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index d634dcd..52f189c 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -50,13 +50,12 @@
* key-value pair. Equivalent to the imaginary std api std::multimap::erase(key, value).
*/
template <typename K, typename V>
-static void eraseByKeyAndValue(std::multimap<K, V>& map, K key, V value) {
- auto iterpair = map.equal_range(key);
-
- for (auto it = iterpair.first; it != iterpair.second; ++it) {
+static void eraseByValue(std::multimap<K, V>& map, const V& value) {
+ for (auto it = map.begin(); it != map.end();) {
if (it->second == value) {
- map.erase(it);
- break;
+ it = map.erase(it);
+ } else {
+ it++;
}
}
}
@@ -76,9 +75,7 @@
// confuse us by reporting the rest of the timeline for one of them. This should happen
// rarely, so we won't lose much data
mTimelines.erase(it);
- // In case we have another input event with a different id and at the same eventTime,
- // only erase this specific inputEventId.
- eraseByKeyAndValue(mEventTimes, eventTime, inputEventId);
+ eraseByValue(mEventTimes, inputEventId);
return;
}
mTimelines.emplace(inputEventId, InputEventTimeline(isDown, eventTime, readTime));
@@ -90,7 +87,8 @@
nsecs_t finishTime) {
const auto it = mTimelines.find(inputEventId);
if (it == mTimelines.end()) {
- // It's possible that an app sends a bad (or late)'Finish' signal, since it's free to do
+ // This could happen if we erased this event when duplicate events were detected. It's
+ // also possible that an app sent a bad (or late) 'Finish' signal, since it's free to do
// anything in its process. Just drop the report and move on.
return;
}
@@ -120,7 +118,8 @@
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
const auto it = mTimelines.find(inputEventId);
if (it == mTimelines.end()) {
- // It's possible that an app sends a bad (or late) 'Timeline' signal, since it's free to do
+ // This could happen if we erased this event when duplicate events were detected. It's
+ // also possible that an app sent a bad (or late) 'Timeline' signal, since it's free to do
// anything in its process. Just drop the report and move on.
return;
}
@@ -166,14 +165,6 @@
}
}
-void LatencyTracker::reportNow() {
- for (const auto& [inputEventId, timeline] : mTimelines) {
- mTimelineProcessor->processTimeline(timeline);
- }
- mTimelines.clear();
- mEventTimes.clear();
-}
-
std::string LatencyTracker::dump(const char* prefix) {
return StringPrintf("%sLatencyTracker:\n", prefix) +
StringPrintf("%s mTimelines.size() = %zu\n", prefix, mTimelines.size()) +
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 289b8ed..4b0c618 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -43,6 +43,12 @@
LatencyTracker(InputEventTimelineProcessor* processor);
/**
* Start keeping track of an event identified by inputEventId. This must be called first.
+ * If duplicate events are encountered (events that have the same eventId), none of them will be
+ * tracked. This is because there is not enough information to correctly track them. The api's
+ * 'trackFinishedEvent' and 'trackGraphicsLatency' only contain the inputEventId, and not the
+ * eventTime. Even if eventTime was provided, there would still be a possibility of having
+ * duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
+ * must drop all duplicate data.
*/
void trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime, nsecs_t readTime);
void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
@@ -50,14 +56,6 @@
void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
- /**
- * Report all collected events immediately, even if some of them are currently incomplete
- * and may receive 'trackFinishedEvent' or 'trackGraphicsLatency' calls in the future.
- * This is useful for tests. Otherwise, tests would have to inject additional "future" events,
- * which is not convenient.
- */
- void reportNow();
-
std::string dump(const char* prefix);
private:
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 1c76dbb..166f358 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -63,9 +63,9 @@
namespace android {
-static const char* DEVICE_PATH = "/dev/input";
+static const char* DEVICE_INPUT_PATH = "/dev/input";
// v4l2 devices go directly into /dev
-static const char* VIDEO_DEVICE_PATH = "/dev";
+static const char* DEVICE_PATH = "/dev";
static constexpr size_t OBFUSCATED_LENGTH = 8;
@@ -685,15 +685,23 @@
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
mINotifyFd = inotify_init();
- mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
- strerror(errno));
- if (isV4lScanningEnabled()) {
- mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
- VIDEO_DEVICE_PATH, strerror(errno));
+
+ std::error_code errorCode;
+ bool isDeviceInotifyAdded = false;
+ if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+ addDeviceInputInotify();
} else {
- mVideoWd = -1;
+ addDeviceInotify();
+ isDeviceInotifyAdded = true;
+ if (errorCode) {
+ ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+ errorCode.message().c_str());
+ }
+ }
+
+ if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
+ addDeviceInotify();
+ } else {
ALOGI("Video device scanning disabled");
}
@@ -733,6 +741,23 @@
::close(mWakeWritePipeFd);
}
+/**
+ * On devices that don't have any input devices (like some development boards), the /dev/input
+ * directory will be absent. However, the user may still plug in an input device at a later time.
+ * Add watch for contents of /dev/input only when /dev/input appears.
+ */
+void EventHub::addDeviceInputInotify() {
+ mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mDeviceInputWd < 0, "Could not register INotify for %s: %s",
+ DEVICE_INPUT_PATH, strerror(errno));
+}
+
+void EventHub::addDeviceInotify() {
+ mDeviceWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mDeviceWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
+ strerror(errno));
+}
+
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
@@ -1738,14 +1763,24 @@
}
void EventHub::scanDevicesLocked() {
- status_t result = scanDirLocked(DEVICE_PATH);
- if (result < 0) {
- ALOGE("scan dir failed for %s", DEVICE_PATH);
+ status_t result;
+ std::error_code errorCode;
+
+ if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+ result = scanDirLocked(DEVICE_INPUT_PATH);
+ if (result < 0) {
+ ALOGE("scan dir failed for %s", DEVICE_INPUT_PATH);
+ }
+ } else {
+ if (errorCode) {
+ ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+ errorCode.message().c_str());
+ }
}
if (isV4lScanningEnabled()) {
- result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+ result = scanVideoDirLocked(DEVICE_PATH);
if (result != OK) {
- ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+ ALOGE("scan video dir failed for %s", DEVICE_PATH);
}
}
if (mDevices.find(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) == mDevices.end()) {
@@ -2356,23 +2391,25 @@
while (res >= (int)sizeof(*event)) {
event = (struct inotify_event*)(event_buf + event_pos);
if (event->len) {
- if (event->wd == mInputWd) {
- std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
+ if (event->wd == mDeviceInputWd) {
+ std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name;
if (event->mask & IN_CREATE) {
openDeviceLocked(filename);
} else {
ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
closeDeviceByPathLocked(filename);
}
- } else if (event->wd == mVideoWd) {
+ } else if (event->wd == mDeviceWd) {
if (isV4lTouchNode(event->name)) {
- std::string filename = std::string(VIDEO_DEVICE_PATH) + "/" + event->name;
+ std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
if (event->mask & IN_CREATE) {
openVideoDeviceLocked(filename);
} else {
ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
closeVideoDeviceByPathLocked(filename);
}
+ } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE) {
+ addDeviceInputInotify();
}
} else {
LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 1016a2c..3c3f88e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -663,6 +663,9 @@
const std::unordered_map<int32_t, RawLightInfo>& getLightInfoLocked(int32_t deviceId) const
REQUIRES(mLock);
+ void addDeviceInputInotify();
+ void addDeviceInotify();
+
// Protect all internal state.
mutable std::mutex mLock;
@@ -702,8 +705,8 @@
int mWakeReadPipeFd;
int mWakeWritePipeFd;
- int mInputWd;
- int mVideoWd;
+ int mDeviceInputWd;
+ int mDeviceWd = -1;
// Maximum number of signalled FDs to handle at a time.
static const int EPOLL_MAX_EVENTS = 16;
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 7ac2dec..a507632 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -303,7 +303,7 @@
* the device
*/
mDeviceEnabled = false;
- for (const auto& [sensorType, sensor] : mSensors) {
+ for (const auto& [_, sensor] : mSensors) {
// If any sensor is on we will turn on the device.
if (sensor.enabled) {
mDeviceEnabled = true;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 29a0fc7..ac5f6b6 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -925,6 +925,13 @@
mTiltXScale = M_PI / 180;
mTiltYScale = M_PI / 180;
+ if (mRawPointerAxes.tiltX.resolution) {
+ mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution;
+ }
+ if (mRawPointerAxes.tiltY.resolution) {
+ mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution;
+ }
+
mOrientedRanges.haveTilt = true;
mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 00b00e3..ee4d3b8 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3120,6 +3120,16 @@
mWindow->assertNoEvents();
}
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) {
+ sendAndConsumeKeyDown(DEVICE_ID);
+ expectKeyRepeatOnce(1 /*repeatCount*/);
+ NotifyDeviceResetArgs args(10 /*id*/, 20 /*eventTime*/, DEVICE_ID);
+ mDispatcher->notifyDeviceReset(&args);
+ mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT,
+ AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS);
+ mWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
sendAndConsumeKeyDown(1 /* deviceId */);
for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index e7e1937..89c0741 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -16,6 +16,7 @@
#include "../dispatcher/LatencyTracker.h"
+#include <android-base/properties.h>
#include <binder/Binder.h>
#include <gtest/gtest.h>
#include <inttypes.h>
@@ -23,11 +24,16 @@
#define TAG "LatencyTracker_test"
+using android::base::HwTimeoutMultiplier;
using android::inputdispatcher::InputEventTimeline;
using android::inputdispatcher::LatencyTracker;
namespace android::inputdispatcher {
+const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
+ android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+ HwTimeoutMultiplier());
+
InputEventTimeline getTestTimeline() {
InputEventTimeline t(
/*isDown*/ true,
@@ -57,6 +63,8 @@
}
void TearDown() override {}
+ void triggerEventReporting(nsecs_t lastEventTime);
+
void assertReceivedTimeline(const InputEventTimeline& timeline);
/**
* Timelines can be received in any order (order is not guaranteed). So if we are expecting more
@@ -72,8 +80,17 @@
std::deque<InputEventTimeline> mReceivedTimelines;
};
+/**
+ * Send an event that would trigger the reporting of all of the events that are at least as old as
+ * the provided 'lastEventTime'.
+ */
+void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
+ const nsecs_t triggerEventTime =
+ lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
+ mTracker->trackListener(1 /*inputEventId*/, true /*isDown*/, triggerEventTime, 3 /*readTime*/);
+}
+
void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
- mTracker->reportNow();
ASSERT_FALSE(mReceivedTimelines.empty());
const InputEventTimeline& t = mReceivedTimelines.front();
ASSERT_EQ(timeline, t);
@@ -88,7 +105,6 @@
* equal element in B, and for every element in B there is an equal element in A.
*/
void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
- mTracker->reportNow();
ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
for (const InputEventTimeline& expectedTimeline : timelines) {
bool found = false;
@@ -121,6 +137,7 @@
*/
TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
mTracker->trackListener(1 /*inputEventId*/, false /*isDown*/, 2 /*eventTime*/, 3 /*readTime*/);
+ triggerEventReporting(2 /*eventTime*/);
assertReceivedTimeline(InputEventTimeline{false, 2, 3});
}
@@ -130,6 +147,7 @@
TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/,
3 /*consumeTime*/, 4 /*finishTime*/);
+ triggerEventReporting(4 /*eventTime*/);
assertReceivedTimelines({});
}
@@ -141,6 +159,7 @@
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
mTracker->trackGraphicsLatency(1 /*inputEventId*/, connection2, graphicsTimeline);
+ triggerEventReporting(3 /*eventTime*/);
assertReceivedTimelines({});
}
@@ -155,9 +174,30 @@
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
+ triggerEventReporting(expected.eventTime);
assertReceivedTimeline(expected);
}
+/**
+ * Send 2 events with the same inputEventId, but different eventTime's. Ensure that no crash occurs,
+ * and that the tracker drops such events completely.
+ */
+TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
+ constexpr nsecs_t inputEventId = 1;
+ constexpr nsecs_t readTime = 3; // does not matter for this test
+ constexpr bool isDown = true; // does not matter for this test
+
+ // In the following 2 calls to trackListener, the inputEventId's are the same, but event times
+ // are different.
+ mTracker->trackListener(inputEventId, isDown, 1 /*eventTime*/, readTime);
+ mTracker->trackListener(inputEventId, isDown, 2 /*eventTime*/, readTime);
+
+ triggerEventReporting(2 /*eventTime*/);
+ // Since we sent duplicate input events, the tracker should just delete all of them, because it
+ // does not have enough information to properly track them.
+ assertReceivedTimelines({});
+}
+
TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
constexpr int32_t inputEventId1 = 1;
InputEventTimeline timeline1(
@@ -204,6 +244,7 @@
mTracker->trackGraphicsLatency(inputEventId2, connection2,
connectionTimeline2.graphicsTimeline);
// Now both events should be completed
+ triggerEventReporting(timeline2.eventTime);
assertReceivedTimelines({timeline1, timeline2});
}
@@ -228,6 +269,7 @@
mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline);
expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
+ triggerEventReporting(timeline.eventTime);
assertReceivedTimelines(expectedTimelines);
}
@@ -246,6 +288,7 @@
mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
+ triggerEventReporting(expected.eventTime);
assertReceivedTimeline(
InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
}
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..455a1e2
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -0,0 +1,48 @@
+// 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_fuzz {
+ name: "inputflinger_latencytracker_fuzzer",
+ defaults: [
+ "inputflinger_defaults",
+ ],
+ include_dirs: [
+ "frameworks/native/services/inputflinger",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libui",
+ "libutils",
+ "libinput",
+ "libinputflinger",
+ ],
+ srcs: [
+ "LatencyTrackerFuzzer.cpp",
+ ],
+ fuzz_config: {
+ cc: ["android-framework-input@google.com"],
+ },
+}
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
new file mode 100644
index 0000000..4f066ad
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 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 <fuzzer/FuzzedDataProvider.h>
+#include "dispatcher/LatencyTracker.h"
+
+namespace android {
+
+namespace inputdispatcher {
+
+/**
+ * A processor of InputEventTimelines that does nothing with the provided data.
+ */
+class EmptyProcessor : public InputEventTimelineProcessor {
+public:
+ /**
+ * Just ignore the provided timeline
+ */
+ void processTimeline(const InputEventTimeline& timeline) override {
+ for (const auto& [token, connectionTimeline] : timeline.connectionTimelines) {
+ connectionTimeline.isComplete();
+ }
+ };
+};
+
+static sp<IBinder> getConnectionToken(FuzzedDataProvider& fdp,
+ std::array<sp<IBinder>, 10>& tokens) {
+ const bool useExistingToken = fdp.ConsumeBool();
+ if (useExistingToken) {
+ return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)];
+ }
+ return new BBinder();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ EmptyProcessor emptyProcessor;
+ LatencyTracker tracker(&emptyProcessor);
+
+ // Make some pre-defined tokens to ensure that some timelines are complete.
+ std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
+ for (size_t i = 0; i < predefinedTokens.size(); i++) {
+ predefinedTokens[i] = new BBinder();
+ }
+
+ // Randomly invoke LatencyTracker api's until randomness is exhausted.
+ while (fdp.remaining_bytes() > 0) {
+ fdp.PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ int32_t isDown = fdp.ConsumeBool();
+ nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
+ tracker.trackListener(inputEventId, isDown, eventTime, readTime);
+ },
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+ nsecs_t deliveryTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t consumeTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t finishTime = fdp.ConsumeIntegral<nsecs_t>();
+ tracker.trackFinishedEvent(inputEventId, connectionToken, deliveryTime,
+ consumeTime, finishTime);
+ },
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+ for (size_t i = 0; i < graphicsTimeline.size(); i++) {
+ graphicsTimeline[i] = fdp.ConsumeIntegral<nsecs_t>();
+ }
+ tracker.trackGraphicsLatency(inputEventId, connectionToken, graphicsTimeline);
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace inputdispatcher
+
+} // namespace android
\ No newline at end of file
diff --git a/services/memtrackproxy/Android.bp b/services/memtrackproxy/Android.bp
index 7d78f3b..3233cc9 100644
--- a/services/memtrackproxy/Android.bp
+++ b/services/memtrackproxy/Android.bp
@@ -32,7 +32,7 @@
"libcutils",
"libutils",
"android.hardware.memtrack@1.0",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
],
srcs: [
"MemtrackProxy.cpp",
@@ -45,6 +45,6 @@
],
export_shared_lib_headers: [
"android.hardware.memtrack@1.0",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
],
}
diff --git a/services/memtrackproxy/test/Android.bp b/services/memtrackproxy/test/Android.bp
index f943761..1dc21bf 100644
--- a/services/memtrackproxy/test/Android.bp
+++ b/services/memtrackproxy/test/Android.bp
@@ -29,7 +29,7 @@
shared_libs: [
"libbinder_ndk",
"libmemtrackproxy",
- "android.hardware.memtrack-V1-ndk_platform",
+ "android.hardware.memtrack-V1-ndk",
],
test_suites: ["general-tests"],
require_root: true,
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 4151b45..e6b118b 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -36,7 +36,7 @@
"-Wall",
"-Werror",
"-Wextra",
- "-fvisibility=hidden"
+ "-fvisibility=hidden",
],
header_libs: [
@@ -60,6 +60,7 @@
"libbase",
"libhidlbase",
"libfmq",
+ "packagemanager_aidl-cpp",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
@@ -77,6 +78,8 @@
"libsensorprivacy",
"libpermission",
],
+
+ afdo: true,
}
cc_binary {
diff --git a/services/stats/Android.bp b/services/stats/Android.bp
index a472c5f..7fea616 100644
--- a/services/stats/Android.bp
+++ b/services/stats/Android.bp
@@ -16,7 +16,7 @@
cflags: ["-Wall", "-Werror"],
shared_libs: [
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk_platform",
+ "android.frameworks.stats-V1-ndk",
"libbinder_ndk",
"libhidlbase",
"liblog",
@@ -29,7 +29,7 @@
],
export_shared_lib_headers: [
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk_platform",
+ "android.frameworks.stats-V1-ndk",
],
local_include_dirs: [
"include/stats",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index eeb3f3a..9e69283 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -101,7 +101,7 @@
// TODO (marissaw): this library is not used by surfaceflinger. This is here so
// the library compiled in a way that is accessible to system partition when running
// IMapper's VTS.
- required: ["libgralloctypes"]
+ required: ["libgralloctypes"],
}
cc_defaults {
@@ -114,10 +114,7 @@
thin: true,
},
whole_program_vtables: true, // Requires ThinLTO
- pgo: {
- sampling: true,
- profile_file: "surfaceflinger/surfaceflinger.profdata",
- },
+ afdo: true,
// TODO(b/131771163): Fix broken fuzzer support with LTO.
sanitize: {
fuzzer: false,
@@ -247,7 +244,7 @@
"libSurfaceFlingerProp",
],
- logtags: ["EventLog/EventLogTags.logtags"],
+ logtags: ["EventLog/EventLogTags.logtags"],
}
subdirs = [
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 8c97f12..636555e 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -327,7 +327,7 @@
: Hwc2::IComposerClient::Composition::DEVICE;
}
- compositionState->buffer = mBufferInfo.mBuffer->getBuffer();
+ compositionState->buffer = getBuffer();
compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
? 0
: mBufferInfo.mBufferSlot;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index e26ab11..82a9ae2 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -326,7 +326,7 @@
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
- LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId));
+ LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
status_t result =
mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -641,7 +641,7 @@
}
status_t VirtualDisplaySurface::refreshOutputBuffer() {
- LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId));
+ LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
if (mOutputProducerSlot >= 0) {
mSource[SOURCE_SINK]->cancelBuffer(
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4d804fa..da7ff71 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -134,6 +134,7 @@
mDrawingState.frameTimelineInfo = {};
mDrawingState.postTime = -1;
mDrawingState.destinationFrame.makeInvalid();
+ mDrawingState.isTrustedOverlay = false;
mDrawingState.dropInputMode = gui::DropInputMode::NONE;
if (args.flags & ISurfaceComposerClient::eNoColorFill) {
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 43a6e55..2ece51c 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -3,4 +3,5 @@
chaviw@google.com
lpy@google.com
racarr@google.com
-vishnun@google.com
+scroggo@google.com
+vishnun@google.com
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 758cc70..ce793ad 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1957,7 +1957,10 @@
// We received the present fence from the HWC, so we assume it successfully updated
// the mode, hence we update SF.
mSetActiveModePending = false;
- ON_MAIN_THREAD(setActiveModeInternal());
+ {
+ Mutex::Autolock lock(mStateLock);
+ setActiveModeInternal();
+ }
}
if (framePending) {
@@ -2409,6 +2412,7 @@
mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
if (isDisplayConnected && !display->isPoweredOn()) {
+ getRenderEngine().cleanupPostRender();
return;
}
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
index ded3ebb..d78f5e2 100644
--- a/services/surfaceflinger/TimeStats/OWNERS
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -1 +1,2 @@
+adyabr@google.com
alecmouri@google.com
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 673239d..caeff4a 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -63,18 +63,17 @@
return OK;
}
-static status_t startDisplayService() {
+static void startDisplayService() {
using android::frameworks::displayservice::V1_0::implementation::DisplayService;
using android::frameworks::displayservice::V1_0::IDisplayService;
sp<IDisplayService> displayservice = new DisplayService();
status_t err = displayservice->registerAsService();
+ // b/141930622
if (err != OK) {
- ALOGE("Could not register IDisplayService service.");
+ ALOGE("Did not register (deprecated) IDisplayService service.");
}
-
- return err;
}
int main(int, char**) {
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 575e70d..39d7bd9 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -3,7 +3,7 @@
user system
group graphics drmrpc readproc
capabilities SYS_NICE
- onrestart restart zygote
+ onrestart restart --only-if-running zygote
task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 26c91fa..32ad873 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -60,7 +60,7 @@
"android.hardware.graphics.composer@2.1",
],
shared_libs: [
- "android.hardware.graphics.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk",
"android.hardware.graphics.common@1.2",
"libandroid",
"libbase",
diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS
new file mode 100644
index 0000000..d073e2b
--- /dev/null
+++ b/services/vibratorservice/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
index 0de0f9e..1612743 100644
--- a/services/vr/virtual_touchpad/virtual_touchpad.rc
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -2,4 +2,4 @@
class core
user system
group system input uhid
- writepid /dev/cpuset/system/tasks
+ task_profiles VrServiceCapacityNormal
diff --git a/vulkan/README.md b/vulkan/README.md
index 185aa39..144805c 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -14,7 +14,7 @@
## Code Generation
-We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
+We generate several parts of the loader and tools directly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
### Run The Code Generator
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index d1cd397..fa3b260 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -965,6 +965,13 @@
VkResult result = EnumerateDeviceExtensionProperties(physical_dev, nullptr,
&count, nullptr);
if (result == VK_SUCCESS && count) {
+ // Work-around a race condition during Android start-up, that can result
+ // in the second call to EnumerateDeviceExtensionProperties having
+ // another extension. That causes the second call to return
+ // VK_INCOMPLETE. A work-around is to add 1 to "count" and ask for one
+ // more extension property. See: http://anglebug.com/6715 and
+ // internal-to-Google b/206733351.
+ count++;
driver_extensions_ = AllocateDriverExtensionArray(count);
result = (driver_extensions_)
? EnumerateDeviceExtensionProperties(
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index d7fdab5..0c5d61b 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -624,8 +624,10 @@
switch (ext_bit) {
case ProcHook::KHR_android_surface:
case ProcHook::KHR_surface:
+ case ProcHook::KHR_surface_protected_capabilities:
case ProcHook::EXT_swapchain_colorspace:
case ProcHook::KHR_get_surface_capabilities2:
+ case ProcHook::GOOGLE_surfaceless_query:
hook_extensions_.set(ext_bit);
// return now as these extensions do not require HAL support
return;
@@ -701,8 +703,10 @@
case ProcHook::KHR_external_fence_capabilities:
case ProcHook::KHR_get_surface_capabilities2:
case ProcHook::KHR_surface:
+ case ProcHook::KHR_surface_protected_capabilities:
case ProcHook::EXT_debug_report:
case ProcHook::EXT_swapchain_colorspace:
+ case ProcHook::GOOGLE_surfaceless_query:
case ProcHook::ANDROID_native_buffer:
case ProcHook::EXTENSION_CORE_1_0:
case ProcHook::EXTENSION_CORE_1_1:
@@ -913,6 +917,9 @@
loader_extensions.push_back({
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SURFACE_SPEC_VERSION});
+ loader_extensions.push_back(
+ {VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME,
+ VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION});
loader_extensions.push_back({
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
VK_KHR_ANDROID_SURFACE_SPEC_VERSION});
@@ -922,6 +929,8 @@
loader_extensions.push_back({
VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
+ loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME,
+ VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION});
static const VkExtensionProperties loader_debug_report_extension = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
@@ -979,6 +988,8 @@
void QueryPresentationProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties) {
+ ATRACE_CALL();
+
// Request the android-specific presentation properties via GPDP2
VkPhysicalDeviceProperties2 properties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
@@ -994,7 +1005,17 @@
presentation_properties->pNext = nullptr;
presentation_properties->sharedImage = VK_FALSE;
- GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceProperties2) {
+ // >= 1.1 driver, supports core GPDP2 entrypoint.
+ driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ } else if (driver.GetPhysicalDeviceProperties2KHR) {
+ // Old driver, but may support presentation properties
+ // if we have the GPDP2 extension. Otherwise, no presentation
+ // properties supported.
+ driver.GetPhysicalDeviceProperties2KHR(physicalDevice, &properties);
+ }
}
VkResult EnumerateDeviceExtensionProperties(
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 5f37a50..b436db1 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -565,11 +565,13 @@
if (strcmp(name, "VK_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata;
if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace;
if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
+ if (strcmp(name, "VK_GOOGLE_surfaceless_query") == 0) return ProcHook::GOOGLE_surfaceless_query;
if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2;
if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
+ if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities;
if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 047e774..688630c 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -41,11 +41,13 @@
EXT_hdr_metadata,
EXT_swapchain_colorspace,
GOOGLE_display_timing,
+ GOOGLE_surfaceless_query,
KHR_android_surface,
KHR_get_surface_capabilities2,
KHR_incremental_present,
KHR_shared_presentable_image,
KHR_surface,
+ KHR_surface_protected_capabilities,
KHR_swapchain,
ANDROID_external_memory_android_hardware_buffer,
KHR_bind_memory2,
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3ed3eba..5e36adf 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -537,30 +537,6 @@
}
}
-int get_min_buffer_count(ANativeWindow* window,
- uint32_t* out_min_buffer_count) {
- constexpr int kExtraBuffers = 2;
-
- int err;
- int min_undequeued_buffers;
- err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &min_undequeued_buffers);
- if (err != android::OK || min_undequeued_buffers < 0) {
- ALOGE(
- "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
- "value=%d",
- strerror(-err), err, min_undequeued_buffers);
- if (err == android::OK) {
- err = android::UNKNOWN_ERROR;
- }
- return err;
- }
-
- *out_min_buffer_count =
- static_cast<uint32_t>(min_undequeued_buffers + kExtraBuffers);
- return android::OK;
-}
-
} // anonymous namespace
VKAPI_ATTR
@@ -638,44 +614,67 @@
VKAPI_ATTR
VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
- VkPhysicalDevice /*pdev*/,
+ VkPhysicalDevice pdev,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* capabilities) {
ATRACE_CALL();
int err;
- ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
-
int width, height;
- err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
-
int transform_hint;
- err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
-
int max_buffer_count;
- err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count);
- if (err != android::OK) {
- ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
- strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
+ if (surface == VK_NULL_HANDLE) {
+ const InstanceData& instance_data = GetData(pdev);
+ ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+ bool surfaceless_enabled =
+ instance_data.hook_extensions.test(surfaceless);
+ if (!surfaceless_enabled) {
+ // It is an error to pass a surface==VK_NULL_HANDLE unless the
+ // VK_GOOGLE_surfaceless_query extension is enabled
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this
+ // extension for this function is for
+ // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following
+ // four values cannot be known without a surface. Default values will
+ // be supplied anyway, but cannot be relied upon.
+ width = 1000;
+ height = 1000;
+ transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+ max_buffer_count = 10;
+ } else {
+ ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT,
+ &transform_hint);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT,
+ &max_buffer_count);
+ if (err != android::OK) {
+ ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
}
- capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2;
+ capabilities->minImageCount = std::min(max_buffer_count, 3);
capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
capabilities->currentExtent =
@@ -714,23 +713,43 @@
const InstanceData& instance_data = GetData(pdev);
bool wide_color_support = false;
- Surface& surface = *SurfaceFromHandle(surface_handle);
- int err = native_window_get_wide_color_support(surface.window.get(),
- &wide_color_support);
- if (err) {
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- ALOGV("wide_color_support is: %d", wide_color_support);
- wide_color_support =
- wide_color_support &&
+ uint64_t consumer_usage = 0;
+ bool colorspace_ext =
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
+ if (surface_handle == VK_NULL_HANDLE) {
+ ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+ bool surfaceless_enabled =
+ instance_data.hook_extensions.test(surfaceless);
+ if (!surfaceless_enabled) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Support for VK_GOOGLE_surfaceless_query. The EGL loader
+ // unconditionally supports wide color formats, even if they will cause
+ // a SurfaceFlinger fallback. Based on that, wide_color_support will be
+ // set to true in this case.
+ wide_color_support = true;
+
+ // TODO(b/203826952): research proper value; temporarily use the
+ // values seen on Pixel
+ consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
+ } else {
+ Surface& surface = *SurfaceFromHandle(surface_handle);
+ int err = native_window_get_wide_color_support(surface.window.get(),
+ &wide_color_support);
+ if (err) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ ALOGV("wide_color_support is: %d", wide_color_support);
+
+ consumer_usage = surface.consumer_usage;
+ }
+ wide_color_support = wide_color_support && colorspace_ext;
AHardwareBuffer_Desc desc = {};
desc.width = 1;
desc.height = 1;
desc.layers = 1;
- desc.usage = surface.consumer_usage |
- AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+ desc.usage = consumer_usage | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
// We must support R8G8B8A8
@@ -738,6 +757,11 @@
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+ if (colorspace_ext) {
+ all_formats.emplace_back(VkSurfaceFormatKHR{
+ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_BT709_LINEAR_EXT});
+ }
+
if (wide_color_support) {
all_formats.emplace_back(VkSurfaceFormatKHR{
VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
@@ -745,6 +769,10 @@
VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
}
+ // NOTE: Any new formats that are added must be coordinated across different
+ // Android users. This includes the ANGLE team (a layered implementation of
+ // OpenGL-ES).
+
desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
if (AHardwareBuffer_isSupported(&desc)) {
all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -821,6 +849,12 @@
.supportedUsageFlags;
} break;
+ case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
+ VkSurfaceProtectedCapabilitiesKHR* protected_caps =
+ reinterpret_cast<VkSurfaceProtectedCapabilitiesKHR*>(caps);
+ protected_caps->supportsProtected = VK_TRUE;
+ } break;
+
default:
// Ignore all other extension structs
break;
@@ -872,26 +906,51 @@
int err;
int query_value;
- uint32_t min_buffer_count;
- ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
-
- err = get_min_buffer_count(window, &min_buffer_count);
- if (err != android::OK) {
- return VK_ERROR_SURFACE_LOST_KHR;
- }
-
- err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
- if (err != android::OK || query_value < 0) {
- ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
- strerror(-err), err, query_value);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
-
std::vector<VkPresentModeKHR> present_modes;
- if (min_buffer_count < max_buffer_count)
+ if (surface == VK_NULL_HANDLE) {
+ const InstanceData& instance_data = GetData(pdev);
+ ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query;
+ bool surfaceless_enabled =
+ instance_data.hook_extensions.test(surfaceless);
+ if (!surfaceless_enabled) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this
+ // extension for this function is for
+ // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and
+ // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR. We technically cannot
+ // know if VK_PRESENT_MODE_SHARED_MAILBOX_KHR is supported without a
+ // surface, and that cannot be relied upon.
present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
- present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+ present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+ } else {
+ ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
+
+ err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE(
+ "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
+ "value=%d",
+ strerror(-err), err, query_value);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+
+ err =
+ window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE(
+ "NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
+ strerror(-err), err, query_value);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
+
+ if (min_undequeued_buffers + 1 < max_buffer_count)
+ present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
+ present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
+ }
VkPhysicalDevicePresentationPropertiesANDROID present_properties;
QueryPresentationProperties(pdev, &present_properties);
@@ -1210,21 +1269,28 @@
}
}
- uint32_t min_buffer_count;
- err = get_min_buffer_count(window, &min_buffer_count);
- if (err != android::OK) {
+ int query_value;
+ err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+ query_value);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+ const auto mailbox_num_images = std::max(3u, create_info->minImageCount);
+ const auto requested_images =
+ swap_interval ? create_info->minImageCount : mailbox_num_images;
+ uint32_t num_images = requested_images - 1 + min_undequeued_buffers;
- uint32_t num_images =
- std::max(min_buffer_count, create_info->minImageCount);
-
- // Lower layer insists that we have at least two buffers. This is wasteful
- // and we'd like to relax it in the shared case, but not all the pieces are
- // in place for that to work yet. Note we only lie to the lower layer-- we
- // don't want to give the app back a swapchain with extra images (which they
- // can't actually use!).
- err = native_window_set_buffer_count(window, std::max(2u, num_images));
+ // Lower layer insists that we have at least min_undequeued_buffers + 1
+ // buffers. This is wasteful and we'd like to relax it in the shared case,
+ // but not all the pieces are in place for that to work yet. Note we only
+ // lie to the lower layer--we don't want to give the app back a swapchain
+ // with extra images (which they can't actually use!).
+ uint32_t min_buffer_count = min_undequeued_buffers + 1;
+ err = native_window_set_buffer_count(
+ window, std::max(min_buffer_count, num_images));
if (err != android::OK) {
ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
strerror(-err), err);
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index 6a73023..af56764 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -27,11 +27,13 @@
'VK_EXT_hdr_metadata',
'VK_EXT_swapchain_colorspace',
'VK_GOOGLE_display_timing',
+ 'VK_GOOGLE_surfaceless_query',
'VK_KHR_android_surface',
'VK_KHR_get_surface_capabilities2',
'VK_KHR_incremental_present',
'VK_KHR_shared_presentable_image',
'VK_KHR_surface',
+ 'VK_KHR_surface_protected_capabilities',
'VK_KHR_swapchain',
]