Merge sc-v2-dev-plus-aosp-without-vendor@8084891
Bug: 214455710
Merged-In: I10fd54544bee940313f3987247c1841101a9d03a
Change-Id: Iec868d5230dbcf81bb6f4af7cf3bc42d57d6b84d
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 77915d5..e42ee05 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -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/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e97949e..8ccd940 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -371,14 +371,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) {
@@ -412,11 +408,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()) {
@@ -447,7 +438,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());
}
@@ -486,7 +477,6 @@
}
void add_mountinfo() {
- if (!ds.IsZipping()) return;
std::string title = "MOUNT INFO";
mount_points.clear();
DurationReporter duration_reporter(title, true);
@@ -823,11 +813,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.
@@ -928,21 +913,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) {
@@ -1035,10 +1011,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,
@@ -1064,10 +1036,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;
@@ -1079,10 +1047,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(),
@@ -1123,7 +1087,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());
@@ -1131,13 +1095,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) {
@@ -1148,14 +1108,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());
@@ -1163,11 +1121,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});
@@ -1303,10 +1259,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;
@@ -1386,12 +1338,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);
@@ -1846,8 +1792,8 @@
/* Run some operations that require root. */
if (!PropertiesHelper::IsDryRun()) {
- ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
- ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+ ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
+ ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
}
ds.AddDir(RECOVERY_DIR, true);
@@ -2394,11 +2340,6 @@
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.
@@ -2957,10 +2898,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;
}
@@ -3567,10 +3507,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);
}
@@ -4216,10 +4152,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 852b9a8..4a99cd8 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -157,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";
@@ -214,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();
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 0712c0a..28e5ee2 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -240,11 +240,11 @@
EXPECT_GE(st.st_size, 1000000 /* 1MB */);
}
-TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
- EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
- << duration.count() << " s.";
+TEST_F(ZippedBugreportGenerationTest, TakesBetween20And300Seconds) {
+ EXPECT_GE(duration, 20s) << "Expected completion in more than 20s. Actual time "
+ << duration.count() << " ms.";
EXPECT_LE(duration, 300s) << "Expected completion in less than 300s. Actual time "
- << duration.count() << " s.";
+ << duration.count() << " ms.";
}
/**
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 677d6c7..49c1318 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -61,6 +61,10 @@
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*());
};
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index c3256fc..544c69c 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -698,9 +698,6 @@
if (!status.isOk()) {
return status;
}
- if (previousUid != uid) {
- chown_app_profile_dir(packageName, appId, userId);
- }
// Remember inode numbers of cache directories so that we can clear
// contents while CE storage is locked
@@ -726,6 +723,9 @@
if (!status.isOk()) {
return status;
}
+ 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);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index b6f42ad..c796da6 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -244,7 +244,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);
@@ -468,7 +468,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){
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c4ecd07..0f8a732 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -829,7 +829,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;
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/service/service.cpp b/cmds/service/service.cpp
index fe417a3..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>
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 80c0548..32922ca 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -47,6 +47,14 @@
}
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,
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 4374abe..555be1ed7 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -113,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;
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/data/etc/Android.bp b/data/etc/Android.bp
index af8f718..c901c59 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -191,6 +191,12 @@
}
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"],
@@ -239,6 +245,12 @@
}
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"],
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index ec9d554..0970ca5 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -54,6 +54,8 @@
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()
@@ -296,6 +298,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;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 06542f0..056ef0a 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -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
@@ -302,6 +305,14 @@
} 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;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 81e61da..ea2f8d2 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -43,6 +43,8 @@
namespace android {
+using AidlRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+
using AidlServiceManager = android::os::IServiceManager;
using android::binder::Status;
@@ -79,7 +81,24 @@
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();
@@ -90,6 +109,17 @@
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
@@ -442,6 +472,77 @@
: 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
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 269b086..1821729 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -368,7 +368,7 @@
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
pid_t pid = getpid();
String8 name;
- name.appendFormat("Binder:%d_%X", pid, s);
+ name.appendFormat("%d_%X:%s", pid, s, mDriverName.c_str());
return name;
}
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 6286c9c..4ddbce7 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -310,9 +310,9 @@
}
status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, iovec* iovs,
- size_t niovs, const std::function<status_t()>& altPoll) {
- for (size_t i = 0; i < niovs; i++) {
+ 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 on RpcTransport %p: %s", what, connection->rpcTransport.get(),
android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
@@ -321,7 +321,7 @@
connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
iovs, niovs, altPoll);
status != OK) {
- LOG_RPC_DETAIL("Failed to write %s (%zu iovs) on RpcTransport %p, error: %s", what, niovs,
+ 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;
@@ -331,19 +331,18 @@
}
status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, iovec* iovs,
- size_t niovs) {
+ 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 (%zu iovs) on RpcTransport %p, error: %s", what, niovs,
+ 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;
}
- for (size_t i = 0; i < niovs; i++) {
+ for (int i = 0; i < niovs; i++) {
LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 5cad394..f4a0894 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -180,11 +180,10 @@
[[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what, iovec* iovs,
- size_t niovs,
- const std::function<status_t()>& altPoll = nullptr);
+ 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,
- size_t niovs);
+ int niovs);
[[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, Parcel* reply);
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 2182e18..636e5d0 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -44,11 +44,15 @@
}
template <typename SendOrReceive>
- status_t interruptableReadOrWrite(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
+ 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()) {
@@ -74,7 +78,9 @@
while (true) {
msghdr msg{
.msg_iov = iovs,
- .msg_iovlen = niovs,
+ // 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));
@@ -128,13 +134,13 @@
}
}
- status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
+ 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, size_t niovs,
+ 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);
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index c05ea15..3936204 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -275,9 +275,9 @@
RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
: mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
Result<size_t> peek(void* buf, size_t size) override;
- status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::function<status_t()>& altPoll) override;
- status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
+ status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::function<status_t()>& altPoll) override;
private:
@@ -303,16 +303,18 @@
return ret;
}
-status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
+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 (size_t i = 0; i < niovs; i++) {
+ for (int i = 0; i < niovs; i++) {
const iovec& iov = iovs[i];
if (iov.iov_len == 0) {
continue;
@@ -343,16 +345,18 @@
return OK;
}
-status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
+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 (size_t i = 0; i < niovs; i++) {
+ for (int i = 0; i < niovs; i++) {
const iovec& iov = iovs[i];
if (iov.iov_len == 0) {
continue;
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index a44c578..83b97d0 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -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/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 7d14315..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)
@@ -142,8 +142,8 @@
} \
return intr; \
} \
- std::unique_ptr<ITYPE> ITYPE::default_impl; \
- bool ITYPE::setDefaultImpl(std::unique_ptr<ITYPE> impl) { \
+ ::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. */ \
@@ -154,7 +154,7 @@
} \
return false; \
} \
- const std::unique_ptr<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
+ const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
ITYPE::INAME() {} \
ITYPE::~INAME() {}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 240e3c2..ea40db8 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -115,6 +115,17 @@
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();
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index 348bfeb..ade2d94 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -58,10 +58,10 @@
* error - interrupted (failure or trigger)
*/
[[nodiscard]] virtual status_t interruptableWriteFully(
- FdTrigger *fdTrigger, iovec *iovs, size_t niovs,
+ FdTrigger *fdTrigger, iovec *iovs, int niovs,
const std::function<status_t()> &altPoll) = 0;
[[nodiscard]] virtual status_t interruptableReadFully(
- FdTrigger *fdTrigger, iovec *iovs, size_t niovs,
+ FdTrigger *fdTrigger, iovec *iovs, int niovs,
const std::function<status_t()> &altPoll) = 0;
protected:
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/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 77493b3..79c8c8f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -32,16 +32,6 @@
],
}
-// TODO(b/211908498): remove this
-cc_defaults {
- name: "libbinder_ndk_host_user",
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
-
cc_library {
name: "libbinder_ndk",
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index e4df98a..355b3b4 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -32,7 +32,7 @@
"com.android.uwb",
"com.android.virt",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
}
rust_library {
@@ -44,6 +44,7 @@
"libtokio",
],
host_supported: true,
+ vendor_available: true,
target: {
darwin: {
enabled: false,
@@ -52,8 +53,10 @@
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "Tiramisu",
}
rust_library {
@@ -79,7 +82,7 @@
"com.android.uwb",
"com.android.virt",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
lints: "none",
clippy_lints: "none",
}
@@ -137,7 +140,7 @@
"com.android.uwb",
"com.android.virt",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
}
// TODO(b/184872979): remove once the Rust API is created.
@@ -154,7 +157,7 @@
"com.android.uwb",
"com.android.virt",
],
- min_sdk_version: "current",
+ min_sdk_version: "Tiramisu",
}
rust_test {
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 47dcdc2..9dcef42 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -28,8 +28,8 @@
//!
//! [`Tokio`]: crate::Tokio
-use binder::public_api::{BinderAsyncPool, BoxFuture, Strong};
-use binder::{FromIBinder, StatusCode, BinderAsyncRuntime};
+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
@@ -37,12 +37,12 @@
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::public_api::get_interface::<T>(name);
+ return binder::get_interface::<T>(name);
}
let name = name.to_string();
let res = tokio::task::spawn_blocking(move || {
- binder::public_api::get_interface::<T>(&name)
+ binder::get_interface::<T>(&name)
}).await;
// The `is_panic` branch is not actually reachable in Android as we compile
@@ -61,12 +61,12 @@
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::public_api::wait_for_interface::<T>(name);
+ return binder::wait_for_interface::<T>(name);
}
let name = name.to_string();
let res = tokio::task::spawn_blocking(move || {
- binder::public_api::wait_for_interface::<T>(&name)
+ binder::wait_for_interface::<T>(&name)
}).await;
// The `is_panic` branch is not actually reachable in Android as we compile
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 4d6b294..467e51e 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -192,9 +192,6 @@
/// 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);
@@ -270,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.
@@ -536,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`
@@ -772,7 +772,7 @@
native: $native($on_transact),
proxy: $proxy {},
$(async: $async_interface,)?
- stability: $crate::Stability::default(),
+ stability: $crate::binder_impl::Stability::default(),
}
}
};
@@ -811,7 +811,7 @@
$($fname: $fty = $finit),*
},
$(async: $async_interface,)?
- stability: $crate::Stability::default(),
+ stability: $crate::binder_impl::Stability::default(),
}
}
};
@@ -828,9 +828,9 @@
} => {
$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),*
},
@@ -867,7 +867,7 @@
}
}
- impl $crate::Proxy for $proxy
+ impl $crate::binder_impl::Proxy for $proxy
where
$proxy: $interface,
{
@@ -875,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),* })
}
}
@@ -887,19 +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);
+ let mut binder = $crate::binder_impl::Binder::new_with_stability($native(Box::new(inner)), $stability);
#[cfg(not(android_vndk))]
- $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
+ $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::BorrowedParcel<'_>, reply: &mut $crate::BorrowedParcel<'_>) -> $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) => {
@@ -913,19 +913,19 @@
}
}
- fn on_dump(&self, file: &std::fs::File, args: &[&std::ffi::CStr]) -> $crate::Result<()> {
+ 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::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`
// 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,
@@ -936,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
@@ -962,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)?)));
}
}
@@ -970,18 +970,18 @@
}
}
- 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::BorrowedParcel<'_>) -> $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::BorrowedParcel<'_>) -> $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))
}
}
@@ -1004,25 +1004,25 @@
$(
// Async interface trait implementations.
impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
- fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $async_interface<P>>> {
- use $crate::AssociateClass;
+ 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::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
@@ -1031,7 +1031,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)?)));
}
}
@@ -1039,15 +1039,15 @@
}
}
- impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
- fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
+ 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::parcel::SerializeOption for dyn $async_interface<P> + '_ {
- fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
+ 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))
}
}
@@ -1067,11 +1067,11 @@
}
}
- impl<P: $crate::BinderAsyncPool> $crate::ToAsyncInterface<P> for dyn $interface {
+ impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToAsyncInterface<P> for dyn $interface {
type Target = dyn $async_interface<P>;
}
- impl<P: $crate::BinderAsyncPool> $crate::ToSyncInterface for dyn $async_interface<P> {
+ impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToSyncInterface for dyn $async_interface<P> {
type Target = dyn $interface;
}
)?
@@ -1103,29 +1103,29 @@
}
}
- impl $crate::parcel::Serialize for $enum {
- fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $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::BorrowedParcel<'_>) -> $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::BorrowedParcel<'_>) -> $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::BorrowedParcel<'_>) -> $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/lib.rs b/libs/binder/rust/src/lib.rs
index 20d90f7..1d7de98 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -101,45 +101,50 @@
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, ToAsyncInterface, ToSyncInterface, 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 crate::binder_async::{BoxFuture, BinderAsyncPool, BinderAsyncRuntime};
-pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
-pub use native::{add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service, Binder};
-pub use parcel::{BorrowedParcel, Parcel};
-pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
-pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
+pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
+pub use proxy::{
+ get_interface, get_service, wait_for_interface, wait_for_service, DeathRecipient, SpIBinder,
+ WpIBinder,
+};
pub use state::{ProcessState, ThreadState};
+/// 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;
}
-
-/// The public API usable outside AIDL-generated interface crates.
-pub mod public_api {
- pub use super::parcel::{ParcelFileDescriptor, ParcelableHolder};
- pub use super::{
- add_service, force_lazy_services_persist, get_interface, register_lazy_service,
- wait_for_interface,
- };
- pub use super::{
- BinderAsyncPool, BinderFeatures, BoxFuture, 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>;
-}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 206b90c..256fa8b 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -496,7 +496,7 @@
{
let start = self.get_data_position();
let parcelable_size: i32 = self.read()?;
- if parcelable_size < 0 {
+ if parcelable_size < 4 {
return Err(StatusCode::BAD_VALUE);
}
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 61f88b6..0c7e48d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -802,35 +802,32 @@
#[macro_export]
macro_rules! impl_serialize_for_parcelable {
($parcelable:ident) => {
- impl $crate::parcel::Serialize for $parcelable {
+ impl $crate::binder_impl::Serialize for $parcelable {
fn serialize(
&self,
- parcel: &mut $crate::parcel::BorrowedParcel<'_>,
- ) -> $crate::Result<()> {
- <Self as $crate::parcel::SerializeOption>::serialize_option(
- Some(self),
- parcel,
- )
+ parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
+ <Self as $crate::binder_impl::SerializeOption>::serialize_option(Some(self), parcel)
}
}
- impl $crate::parcel::SerializeArray for $parcelable {}
+ impl $crate::binder_impl::SerializeArray for $parcelable {}
- impl $crate::parcel::SerializeOption for $parcelable {
+ impl $crate::binder_impl::SerializeOption for $parcelable {
fn serialize_option(
this: Option<&Self>,
- parcel: &mut $crate::parcel::BorrowedParcel<'_>,
- ) -> $crate::Result<()> {
+ parcel: &mut $crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
if let Some(this) = this {
- use $crate::parcel::Parcelable;
- parcel.write(&$crate::parcel::NON_NULL_PARCELABLE_FLAG)?;
+ use $crate::Parcelable;
+ parcel.write(&$crate::binder_impl::NON_NULL_PARCELABLE_FLAG)?;
this.write_to_parcel(parcel)
} else {
- parcel.write(&$crate::parcel::NULL_PARCELABLE_FLAG)
+ parcel.write(&$crate::binder_impl::NULL_PARCELABLE_FLAG)
}
}
}
- }
+ };
}
/// Implement `Deserialize` trait and friends for a parcelable
@@ -842,54 +839,54 @@
#[macro_export]
macro_rules! impl_deserialize_for_parcelable {
($parcelable:ident) => {
- impl $crate::parcel::Deserialize for $parcelable {
+ impl $crate::binder_impl::Deserialize for $parcelable {
fn deserialize(
- parcel: &$crate::parcel::BorrowedParcel<'_>,
- ) -> $crate::Result<Self> {
- $crate::parcel::DeserializeOption::deserialize_option(parcel)
+ 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::parcel::BorrowedParcel<'_>,
- ) -> $crate::Result<()> {
+ parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
let status: i32 = parcel.read()?;
- if status == $crate::parcel::NULL_PARCELABLE_FLAG {
+ if status == $crate::binder_impl::NULL_PARCELABLE_FLAG {
Err($crate::StatusCode::UNEXPECTED_NULL)
} else {
- use $crate::parcel::Parcelable;
+ use $crate::Parcelable;
self.read_from_parcel(parcel)
}
}
}
- impl $crate::parcel::DeserializeArray for $parcelable {}
+ impl $crate::binder_impl::DeserializeArray for $parcelable {}
- impl $crate::parcel::DeserializeOption for $parcelable {
+ impl $crate::binder_impl::DeserializeOption for $parcelable {
fn deserialize_option(
- parcel: &$crate::parcel::BorrowedParcel<'_>,
- ) -> $crate::Result<Option<Self>> {
+ 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::parcel::BorrowedParcel<'_>,
- ) -> $crate::Result<()> {
+ parcel: &$crate::binder_impl::BorrowedParcel<'_>,
+ ) -> std::result::Result<(), $crate::StatusCode> {
let status: i32 = parcel.read()?;
- if status == $crate::parcel::NULL_PARCELABLE_FLAG {
+ if status == $crate::binder_impl::NULL_PARCELABLE_FLAG {
*this = None;
Ok(())
} else {
- use $crate::parcel::Parcelable;
+ use $crate::Parcelable;
this.get_or_insert_with(Self::default)
.read_from_parcel(parcel)
}
}
}
- }
+ };
}
impl<T: Serialize> Serialize for Box<T> {
@@ -918,7 +915,7 @@
#[cfg(test)]
mod tests {
- use crate::Parcel;
+ use crate::parcel::Parcel;
use super::*;
#[test]
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index b4282b2..d58e839 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -15,9 +15,11 @@
*/
use crate::binder::Stability;
-use crate::error::{Result, StatusCode};
-use crate::parcel::{Parcel, BorrowedParcel, Parcelable};
-use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
+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;
@@ -53,12 +55,6 @@
Parcel(Parcel),
}
-impl Default for ParcelableHolderData {
- fn default() -> Self {
- ParcelableHolderData::Empty
- }
-}
-
/// A container that can hold any arbitrary `Parcelable`.
///
/// This type is currently used for AIDL parcelable fields.
@@ -66,7 +62,7 @@
/// `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, Default)]
+#[derive(Debug)]
pub struct ParcelableHolder {
// This is a `Mutex` because of `get_parcelable`
// which takes `&self` for consistency with C++.
@@ -97,7 +93,7 @@
}
/// Set the parcelable contained in this `ParcelableHolder`.
- pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
+ pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<(), StatusCode>
where
T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
@@ -126,7 +122,7 @@
/// * `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>>>
+ pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>, StatusCode>
where
T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
{
@@ -176,11 +172,28 @@
}
}
-impl_serialize_for_parcelable!(ParcelableHolder);
-impl_deserialize_for_parcelable!(ParcelableHolder);
+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<()> {
+ fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
parcel.write(&self.stability)?;
let mut data = self.data.lock().unwrap();
@@ -219,7 +232,7 @@
}
}
- fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
+ fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
self.stability = parcel.read()?;
let data_size: i32 = parcel.read()?;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 760d862..12bfde7 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -312,17 +312,6 @@
}
}
- 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) };
@@ -412,6 +401,17 @@
)
})
}
+
+ 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 {
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 80dc476..50daf1c 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -17,11 +17,13 @@
//! Rust Binder crate integration tests
use binder::{declare_binder_enum, declare_binder_interface};
-use binder::parcel::BorrowedParcel;
-use binder::{
- Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
- FIRST_CALL_TRANSACTION,
+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;
@@ -120,7 +122,7 @@
}
impl Interface for TestService {
- fn dump(&self, _file: &File, args: &[&CStr]) -> binder::Result<()> {
+ 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(())
@@ -128,22 +130,22 @@
}
impl ITest for TestService {
- fn test(&self) -> binder::Result<String> {
+ fn test(&self) -> Result<String, StatusCode> {
Ok(self.s.clone())
}
- fn get_dump_args(&self) -> binder::Result<Vec<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) -> binder::Result<String> {
+ 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) -> binder::Result<bool> {
+ fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
Ok(binder::is_handling_transaction())
}
}
@@ -151,31 +153,31 @@
/// 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) -> binder::Result<Vec<String>>;
+ 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) -> binder::Result<bool>;
+ 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, binder::Result<String>>;
+ fn test(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>>;
/// Return the arguments sent via dump
- fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>>;
+ 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, binder::Result<String>>;
+ 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, binder::Result<bool>>;
+ fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>>;
}
declare_binder_interface! {
@@ -193,7 +195,7 @@
code: TransactionCode,
_data: &BorrowedParcel<'_>,
reply: &mut BorrowedParcel<'_>,
-) -> binder::Result<()> {
+) -> Result<(), StatusCode> {
match code.try_into()? {
TestTransactionCode::Test => reply.write(&service.test()?),
TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
@@ -203,21 +205,21 @@
}
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_dump_args(&self) -> binder::Result<Vec<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) -> binder::Result<String> {
+ fn get_selinux_context(&self) -> Result<String, StatusCode> {
let reply = self.binder.transact(
TestTransactionCode::GetSelinuxContext as TransactionCode,
0,
@@ -226,7 +228,7 @@
reply.read()
}
- fn get_is_handling_transaction(&self) -> binder::Result<bool> {
+ fn get_is_handling_transaction(&self) -> Result<bool, StatusCode> {
let reply = self.binder.transact(
TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
0,
@@ -237,7 +239,7 @@
}
impl<P: binder::BinderAsyncPool> IATest<P> for BpTest {
- fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+ 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(())),
@@ -245,7 +247,7 @@
)
}
- fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
+ 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(())),
@@ -253,7 +255,7 @@
)
}
- fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+ 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(())),
@@ -261,7 +263,7 @@
)
}
- fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, binder::Result<bool>> {
+ 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(())),
@@ -271,40 +273,40 @@
}
impl ITest for Binder<BnTest> {
- fn test(&self) -> binder::Result<String> {
+ fn test(&self) -> Result<String, StatusCode> {
self.0.test()
}
- fn get_dump_args(&self) -> binder::Result<Vec<String>> {
+ fn get_dump_args(&self) -> Result<Vec<String>, StatusCode> {
self.0.get_dump_args()
}
- fn get_selinux_context(&self) -> binder::Result<String> {
+ fn get_selinux_context(&self) -> Result<String, StatusCode> {
self.0.get_selinux_context()
}
- fn get_is_handling_transaction(&self) -> binder::Result<bool> {
+ 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, binder::Result<String>> {
+ 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, binder::Result<Vec<String>>> {
+ 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, binder::Result<String>> {
+ 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, binder::Result<bool>> {
+ 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 })
}
@@ -325,7 +327,7 @@
_code: TransactionCode,
_data: &BorrowedParcel<'_>,
_reply: &mut BorrowedParcel<'_>,
-) -> binder::Result<()> {
+) -> Result<(), StatusCode> {
Ok(())
}
@@ -363,9 +365,12 @@
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 binder_tokio::Tokio;
@@ -743,8 +748,7 @@
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn ITest> =
- binder::get_interface(service_name)
- .expect("Did not get test binder service");
+ 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");
@@ -925,7 +929,7 @@
let service2 = service2.as_binder();
let parcel = service1.prepare_transact().unwrap();
- let res = service2.submit_transact(super::TestTransactionCode::Test as binder::TransactionCode, parcel, 0);
+ let res = service2.submit_transact(super::TestTransactionCode::Test as TransactionCode, parcel, 0);
match res {
Ok(_) => panic!("submit_transact should fail"),
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 1fc761e..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, BorrowedParcel, ExceptionCode, Interface, 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;
@@ -113,7 +114,7 @@
code: TransactionCode,
parcel: &BorrowedParcel<'_>,
reply: &mut BorrowedParcel<'_>,
-) -> Result<()> {
+) -> Result<(), StatusCode> {
match code {
bindings::Transaction_TEST_BOOL => {
assert_eq!(parcel.read::<bool>()?, true);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 86da588..ff55d6e 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 {
@@ -69,7 +76,11 @@
"libgmock",
],
compile_multilib: "32",
- multilib: { lib32: { suffix: "" } },
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ },
cflags: ["-DBINDER_IPC_32BIT=1"],
test_suites: ["vts"],
require_root: true,
@@ -84,7 +95,11 @@
enabled: false,
},
},
- srcs: ["binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp"],
+ srcs: [
+ "binderParcelUnitTest.cpp",
+ "binderBinderUnitTest.cpp",
+ "binderStatusUnitTest.cpp",
+ ],
shared_libs: [
"libbinder",
"libcutils",
@@ -112,7 +127,10 @@
static_libs: [
"libgmock",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -179,7 +197,6 @@
},
defaults: [
"binder_test_defaults",
- "libbinder_ndk_host_user",
"libbinder_tls_shared_deps",
],
@@ -232,7 +249,10 @@
"libbinder_tls_test_utils",
"libbinder_tls_static",
],
- test_suites: ["general-tests", "device-tests"],
+ test_suites: [
+ "general-tests",
+ "device-tests",
+ ],
}
cc_benchmark {
@@ -348,7 +368,10 @@
"liblog",
"libutils",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -402,7 +425,10 @@
"binderStabilityTestIface-ndk",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 63a4b2c..700940a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1220,6 +1220,19 @@
EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
}
+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();
+
+ EXPECT_EQ(sm->registerForNotifications(String16("RogerRafa"), cb), OK);
+ EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK);
+}
+
class BinderLibRpcTestBase : public BinderLibTest {
public:
void SetUp() override {
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/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/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 1fd2c62..79cc15f 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -13,11 +13,13 @@
shared_libs: [
"libbase",
"libbpf_bcc",
- "libbpf_android",
+ "libbpf_minimal",
"liblog",
- "libnetdutils"
],
- header_libs: ["bpf_prog_headers"],
+ header_libs: [
+ "bpf_prog_headers",
+ "bpf_headers",
+ ],
cflags: [
"-Werror",
"-Wall",
@@ -32,15 +34,18 @@
shared_libs: [
"libbase",
"libbpf_bcc",
- "libbpf_android",
+ "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..1513eca 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -27,6 +27,7 @@
#include <gtest/gtest.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
@@ -40,24 +41,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 +125,7 @@
EXPECT_EQ(activeSum, policySum);
}
-TEST(TimeInStateTest, SingleUidTimesConsistent) {
+TEST_F(TimeInStateTest, SingleUidTimesConsistent) {
auto times = getUidCpuFreqTimes(0);
ASSERT_TRUE(times.has_value());
@@ -127,7 +135,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 +171,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 +205,7 @@
}
}
-TEST(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
+TEST_F(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
auto allUid = getUidsCpuFreqTimes();
auto total = getTotalCpuFreqTimes();
@@ -222,7 +230,7 @@
}
}
-TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
+TEST_F(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -246,7 +254,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimes) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimes) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &map : maps) {
@@ -264,7 +272,7 @@
}
}
-TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
+TEST_F(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
uint64_t lastUpdate = 0;
auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate);
ASSERT_TRUE(map1.has_value());
@@ -299,7 +307,7 @@
}
}
-TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+TEST_F(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &map : maps) {
@@ -328,7 +336,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 +352,7 @@
}
}
-TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
+TEST_F(TimeInStateTest, AllUidTimeInStateMonotonic) {
auto map1 = getUidsCpuFreqTimes();
ASSERT_TRUE(map1.has_value());
sleep(1);
@@ -365,7 +373,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
auto map1 = getUidsConcurrentTimes();
ASSERT_TRUE(map1.has_value());
ASSERT_FALSE(map1->empty());
@@ -393,7 +401,7 @@
}
}
-TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
+TEST_F(TimeInStateTest, AllUidTimeInStateSanityCheck) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -414,7 +422,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &concurrentMap : maps) {
@@ -441,7 +449,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
uint32_t uid = 0;
{
// Find an unused UID
@@ -463,7 +471,7 @@
ASSERT_FALSE(deleteMapEntry(fd, &key));
}
-TEST(TimeInStateTest, AllUidTimesConsistent) {
+TEST_F(TimeInStateTest, AllUidTimesConsistent) {
auto tisMap = getUidsCpuFreqTimes();
ASSERT_TRUE(tisMap.has_value());
@@ -481,7 +489,7 @@
}
}
-TEST(TimeInStateTest, RemoveUid) {
+TEST_F(TimeInStateTest, RemoveUid) {
uint32_t uid = 0;
{
// Find an unused UID
@@ -547,7 +555,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 +591,7 @@
return nullptr;
}
-TEST(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
+TEST_F(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
uint64_t startTimeNs = timeNanos();
sem_init(&pingsem, 0, 1);
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 9f0754b..61e4a98 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -84,4 +84,14 @@
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 b1496ba..6d6e008 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -53,6 +53,11 @@
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/types/Android.bp b/libs/gralloc/types/Android.bp
index cda9e19..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,7 +47,7 @@
min_sdk_version: "29",
srcs: [
- "Gralloc4.cpp"
+ "Gralloc4.cpp",
],
shared_libs: [
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/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 6882ea3..0128859 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -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/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/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 24087ac..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_bcc",
- "libbpf_android",
"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/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 5b69f96..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_bcc",
- "libbpf_android",
"libcutils",
"libgfxstats",
"libgpumem",
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/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/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0ee9fb3..a56827e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -134,6 +134,68 @@
return true;
}
+float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(
+ const LayerRequirement& layer, const RefreshRate& refreshRate) const {
+ constexpr float kScoreForFractionalPairs = .8f;
+
+ const auto displayPeriod = refreshRate.getVsyncPeriod();
+ const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
+ if (layer.vote == LayerVoteType::ExplicitDefault) {
+ // Find the actual rate the layer will render, assuming
+ // that layerPeriod is the minimal period to render a frame.
+ // For example if layerPeriod is 20ms and displayPeriod is 16ms,
+ // then the actualLayerPeriod will be 32ms, because it is the
+ // smallest multiple of the display period which is >= layerPeriod.
+ auto actualLayerPeriod = displayPeriod;
+ int multiplier = 1;
+ while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
+ multiplier++;
+ actualLayerPeriod = displayPeriod * multiplier;
+ }
+
+ // Because of the threshold we used above it's possible that score is slightly
+ // above 1.
+ return std::min(1.0f,
+ static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
+ }
+
+ if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
+ layer.vote == LayerVoteType::Heuristic) {
+ if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
+ return kScoreForFractionalPairs;
+ }
+
+ // Calculate how many display vsyncs we need to present a single frame for this
+ // layer
+ const auto [displayFramesQuotient, displayFramesRemainder] =
+ getDisplayFrames(layerPeriod, displayPeriod);
+ static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
+ if (displayFramesRemainder == 0) {
+ // Layer desired refresh rate matches the display rate.
+ return 1.0f;
+ }
+
+ if (displayFramesQuotient == 0) {
+ // Layer desired refresh rate is higher than the display rate.
+ return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
+ (1.0f / (MAX_FRAMES_TO_FIT + 1));
+ }
+
+ // Layer desired refresh rate is lower than the display rate. Check how well it fits
+ // the cadence.
+ auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
+ int iter = 2;
+ while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
+ diff = diff - (displayPeriod - diff);
+ iter++;
+ }
+
+ return (1.0f / iter);
+ }
+
+ return 0;
+}
+
float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
const RefreshRate& refreshRate,
bool isSeamlessSwitch) const {
@@ -153,51 +215,6 @@
return ratio * ratio;
}
- const auto displayPeriod = refreshRate.getVsyncPeriod();
- const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
- if (layer.vote == LayerVoteType::ExplicitDefault) {
- // Find the actual rate the layer will render, assuming
- // that layerPeriod is the minimal time to render a frame
- auto actualLayerPeriod = displayPeriod;
- int multiplier = 1;
- while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
- multiplier++;
- actualLayerPeriod = displayPeriod * multiplier;
- }
- return std::min(1.0f,
- static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
- }
-
- if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
- layer.vote == LayerVoteType::Heuristic) {
- // Calculate how many display vsyncs we need to present a single frame for this
- // layer
- const auto [displayFramesQuotient, displayFramesRemainder] =
- getDisplayFrames(layerPeriod, displayPeriod);
- static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
- if (displayFramesRemainder == 0) {
- // Layer desired refresh rate matches the display rate.
- return 1.0f * seamlessness;
- }
-
- if (displayFramesQuotient == 0) {
- // Layer desired refresh rate is higher than the display rate.
- return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
- (1.0f / (MAX_FRAMES_TO_FIT + 1));
- }
-
- // Layer desired refresh rate is lower than the display rate. Check how well it fits
- // the cadence.
- auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
- int iter = 2;
- while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
- diff = diff - (displayPeriod - diff);
- iter++;
- }
-
- return (1.0f / iter) * seamlessness;
- }
-
if (layer.vote == LayerVoteType::ExplicitExact) {
const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate);
if (mSupportsFrameRateOverride) {
@@ -210,7 +227,18 @@
return divider == 1;
}
- return 0;
+ // If the layer frame rate is a divider of the refresh rate it should score
+ // the highest score.
+ if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+ return 1.0f * seamlessness;
+ }
+
+ // The layer frame rate is not a divider of the refresh rate,
+ // there is a small penalty attached to the score to favor the frame rates
+ // the exactly matches the display refresh rate or a multiple.
+ constexpr float kNonExactMatchingPenalty = 0.95f;
+ return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness *
+ kNonExactMatchingPenalty;
}
struct RefreshRateScore {
@@ -422,7 +450,7 @@
const auto layerScore =
calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch);
- ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
+ ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
scores[i].refreshRate->getName().c_str(), layerScore);
scores[i].score += weight * layerScore;
}
@@ -583,7 +611,7 @@
template <typename Iter>
const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
- constexpr auto EPSILON = 0.001f;
+ constexpr auto kEpsilon = 0.0001f;
const RefreshRate* bestRefreshRate = begin->refreshRate;
float max = begin->score;
for (auto i = begin; i != end; ++i) {
@@ -592,7 +620,7 @@
ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
- if (score > max * (1 + EPSILON)) {
+ if (score > max * (1 + kEpsilon)) {
max = score;
bestRefreshRate = refreshRate;
}
@@ -945,6 +973,17 @@
return static_cast<int>(numPeriodsRounded);
}
+bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
+ if (smaller.getValue() > bigger.getValue()) {
+ return isFractionalPairOrMultiple(bigger, smaller);
+ }
+
+ const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
+ constexpr float kCoef = 1000.f / 1001.f;
+ return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) ||
+ bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef));
+}
+
void RefreshRateConfigs::dump(std::string& result) const {
std::lock_guard lock(mLock);
base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 21867cc..99f217c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -344,6 +344,10 @@
// layer refresh rate.
static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+ // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
+ // for an integer t.
+ static bool isFractionalPairOrMultiple(Fps, Fps);
+
using UidToFrameRateOverride = std::map<uid_t, Fps>;
// Returns the frame rate override for each uid.
//
@@ -446,6 +450,9 @@
float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
bool isSeamlessSwitch) const REQUIRES(mLock);
+ float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&,
+ const RefreshRate&) const REQUIRES(mLock);
+
void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
void initializeIdleTimer();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 615af02..ce793ad 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2412,6 +2412,7 @@
mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
if (isDisplayConnected && !display->isPoweredOn()) {
+ getRenderEngine().cleanupPostRender();
return;
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index c1dba2b..77b75ab 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -98,9 +98,15 @@
static inline const DisplayModeId HWC_CONFIG_ID_30 = DisplayModeId(4);
static inline const DisplayModeId HWC_CONFIG_ID_25 = DisplayModeId(5);
static inline const DisplayModeId HWC_CONFIG_ID_50 = DisplayModeId(6);
+ static inline const DisplayModeId HWC_CONFIG_ID_24 = DisplayModeId(7);
+ static inline const DisplayModeId HWC_CONFIG_ID_24_FRAC = DisplayModeId(8);
+ static inline const DisplayModeId HWC_CONFIG_ID_30_FRAC = DisplayModeId(9);
+ static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10);
// Test configs
DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+ DisplayModePtr mConfig60Frac =
+ createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs());
DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
DisplayModePtr mConfig90DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
@@ -116,9 +122,15 @@
DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
DisplayModePtr mConfig30DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+ DisplayModePtr mConfig30Frac =
+ createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs());
+ DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs());
DisplayModePtr mConfig25DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
+ DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs());
+ DisplayModePtr mConfig24Frac =
+ createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs());
// Test device configurations
// The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -145,6 +157,11 @@
mConfig50};
DisplayModes m60_120Device = {mConfig60, mConfig120};
+ // This is a typical TV configuration.
+ DisplayModes m24_25_30_50_60WithFracDevice = {mConfig24, mConfig24Frac, mConfig25,
+ mConfig30, mConfig30Frac, mConfig50,
+ mConfig60, mConfig60Frac};
+
// Expected RefreshRate objects
RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)};
RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
@@ -158,7 +175,6 @@
RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)};
RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)};
-private:
DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
ui::Size resolution = ui::Size());
};
@@ -1230,7 +1246,109 @@
const auto& refreshRate =
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
- << "Expecting " << test.first << "fps => " << test.second << "Hz";
+ << "Expecting " << test.first << "fps => " << test.second << "Hz"
+ << " but it was " << refreshRate.getFps();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) {
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Test that 23.976 will choose 24 if 23.976 is not supported
+ {
+ android::DisplayModes modes = {mConfig24, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = Fps(23.976f);
+ lr.name = "ExplicitExactOrMultiple 23.976 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 24 will choose 23.976 if 24 is not supported
+ {
+ android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(24.f);
+ lr.name = "ExplicitExactOrMultiple 24 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 29.97 will prefer 59.94 over 60 and 30
+ {
+ android::DisplayModes modes = {mConfig24, mConfig24Frac, mConfig25,
+ mConfig30, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(29.97f);
+ lr.name = "ExplicitExactOrMultiple 29.97f fps";
+ EXPECT_EQ(HWC_CONFIG_ID_60_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) {
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Test that voting for supported refresh rate will select this refresh rate
+ {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) {
+ lr.vote = LayerVoteType::ExplicitExact;
+ lr.desiredRefreshRate = Fps(desiredRefreshRate);
+ std::stringstream ss;
+ ss << "ExplicitExact " << desiredRefreshRate << " fps";
+ lr.name = ss.str();
+
+ auto selecteRefreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+
+ EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate))
+ << "Expecting " << lr.desiredRefreshRate << " but it was "
+ << selecteRefreshRate.getFps();
+ }
+ }
+
+ // Test that 23.976 will choose 24 if 23.976 is not supported
+ {
+ android::DisplayModes modes = {mConfig24, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.vote = LayerVoteType::ExplicitExact;
+ lr.desiredRefreshRate = Fps(23.976f);
+ lr.name = "ExplicitExact 23.976 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 24 will choose 23.976 if 24 is not supported
+ {
+ android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(24.f);
+ lr.name = "ExplicitExact 24 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
}
}
@@ -2028,6 +2146,100 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f},
+ LayerRequirement{.weight = 0.5f}};
+ auto& explicitDefaultLayer = layers[0];
+ auto& explicitExactOrMultipleLayer = layers[1];
+
+ explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
+ explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+
+ explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault;
+ explicitDefaultLayer.name = "ExplicitDefault";
+ explicitDefaultLayer.desiredRefreshRate = Fps(59.94f);
+
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+// b/190578904
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) {
+ constexpr int kMinRefreshRate = 10;
+ constexpr int kMaxRefreshRate = 240;
+
+ DisplayModes displayModes;
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ constexpr int32_t kGroup = 0;
+ const auto refreshRate = Fps(static_cast<float>(fps));
+ displayModes.push_back(
+ createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs()));
+ }
+
+ const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(displayModes,
+ /*currentConfigId=*/displayModes[0]->getId());
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
+ layers[0].desiredRefreshRate = fps;
+ layers[0].vote = vote;
+ EXPECT_EQ(fps.getIntValue(),
+ refreshRateConfigs->getBestRefreshRate(layers, globalSignals)
+ .getFps()
+ .getIntValue())
+ << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote);
+ };
+
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const auto refreshRate = Fps(static_cast<float>(fps));
+ testRefreshRate(refreshRate, LayerVoteType::Heuristic);
+ testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
+ testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
+ testRefreshRate(refreshRate, LayerVoteType::ExplicitExact);
+ }
+}
+
+// b/190578904
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_conflictingVotes) {
+ const DisplayModes displayModes = {
+ createDisplayMode(DisplayModeId(0), 0, Fps(43.0f).getPeriodNsecs()),
+ createDisplayMode(DisplayModeId(1), 0, Fps(53.0f).getPeriodNsecs()),
+ createDisplayMode(DisplayModeId(2), 0, Fps(55.0f).getPeriodNsecs()),
+ createDisplayMode(DisplayModeId(3), 0, Fps(60.0f).getPeriodNsecs()),
+ };
+
+ const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(displayModes,
+ /*currentConfigId=*/displayModes[0]->getId());
+
+ const auto layers = std::vector<LayerRequirement>{
+ LayerRequirement{
+ .vote = LayerVoteType::ExplicitDefault,
+ .desiredRefreshRate = Fps(43.0f),
+ .seamlessness = Seamlessness::SeamedAndSeamless,
+ .weight = 0.41f,
+ },
+ LayerRequirement{
+ .vote = LayerVoteType::ExplicitExactOrMultiple,
+ .desiredRefreshRate = Fps(53.0f),
+ .seamlessness = Seamlessness::SeamedAndSeamless,
+ .weight = 0.41f,
+ },
+ };
+
+ EXPECT_EQ(53,
+ refreshRateConfigs->getBestRefreshRate(layers, globalSignals).getFps().getIntValue());
+}
+
TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
EXPECT_TRUE(mExpected60Config < mExpected90Config);
EXPECT_FALSE(mExpected60Config < mExpected60Config);
@@ -2123,6 +2335,33 @@
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f)));
}
+TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f)));
+
+ const std::vector<float> refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f};
+ for (auto refreshRate : refreshRates) {
+ EXPECT_FALSE(
+ RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate)));
+ }
+
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f)));
+}
+
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/