Merge "RpcSession attaches/detaches JVM for Java thread"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c9a7c7b..8f466ca 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1240,8 +1240,15 @@
if (status == OK) {
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
std::chrono::duration<double> elapsed_seconds;
- status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
+ if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+ service == String16("meminfo")) {
+ // Use a longer timeout for meminfo, since 30s is not always enough.
+ status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ } else {
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ }
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index d6807ff..643b2c2 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -4,7 +4,6 @@
jsharkey@android.com
maco@google.com
mast@google.com
-mathieuc@google.com
narayan@google.com
ngeoffray@google.com
rpl@google.com
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 15f0c5b..210f977 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1231,6 +1231,14 @@
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files =
+ ::android::base::GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
PrepareArgs(dexoptanalyzer_bin);
}
@@ -1363,10 +1371,12 @@
return kSecondaryDexAccessReadOk;
} else {
if (errno == ENOENT) {
- LOG(INFO) << "Secondary dex does not exist: " << dex_path;
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+ "Secondary dex does not exist: %s", dex_path.c_str());
return kSecondaryDexAccessDoesNotExist;
} else {
- PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not access secondary dex: %s (%d)", dex_path.c_str(), errno);
return errno == EACCES
? kSecondaryDexAccessPermissionError
: kSecondaryDexAccessIOError;
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index e847626..b661684 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -283,6 +283,13 @@
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
if (target_sdk_version != 0) {
AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 02321cd..628381c 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -179,6 +179,17 @@
return transact(SET_RPC_CLIENT_TRANSACTION, data, &reply);
}
+void IBinder::withLock(const std::function<void()>& doWithLock) {
+ BBinder* local = localBinder();
+ if (local) {
+ local->withLock(doWithLock);
+ return;
+ }
+ BpBinder* proxy = this->remoteBinder();
+ LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote");
+ proxy->withLock(doWithLock);
+}
+
// ---------------------------------------------------------------------------
class BBinder::RpcServerLink : public IBinder::DeathRecipient {
@@ -311,15 +322,13 @@
return NO_ERROR;
}
-void BBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
+void* BBinder::attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) {
Extras* e = getOrCreateExtras();
- if (!e) return; // out of memory
+ LOG_ALWAYS_FATAL_IF(!e, "no memory");
AutoMutex _l(e->mLock);
- e->mObjects.attach(objectID, object, cleanupCookie, func);
+ return e->mObjects.attach(objectID, object, cleanupCookie, func);
}
void* BBinder::findObject(const void* objectID) const
@@ -331,13 +340,20 @@
return e->mObjects.find(objectID);
}
-void BBinder::detachObject(const void* objectID)
-{
+void* BBinder::detachObject(const void* objectID) {
Extras* e = mExtras.load(std::memory_order_acquire);
- if (!e) return;
+ if (!e) return nullptr;
AutoMutex _l(e->mLock);
- e->mObjects.detach(objectID);
+ return e->mObjects.detach(objectID);
+}
+
+void BBinder::withLock(const std::function<void()>& doWithLock) {
+ Extras* e = getOrCreateExtras();
+ LOG_ALWAYS_FATAL_IF(!e, "no memory");
+
+ AutoMutex _l(e->mLock);
+ doWithLock();
}
BBinder* BBinder::localBinder()
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 5e44a0f..3099296 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -61,22 +61,22 @@
kill();
}
-void BpBinder::ObjectManager::attach(
- const void* objectID, void* object, void* cleanupCookie,
- IBinder::object_cleanup_func func)
-{
+void* BpBinder::ObjectManager::attach(const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func) {
entry_t e;
e.object = object;
e.cleanupCookie = cleanupCookie;
e.func = func;
- if (mObjects.indexOfKey(objectID) >= 0) {
- ALOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
- objectID, this, object);
- return;
+ if (ssize_t idx = mObjects.indexOfKey(objectID); idx >= 0) {
+ ALOGI("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object "
+ "ID already in use",
+ objectID, this, object);
+ return mObjects[idx].object;
}
mObjects.add(objectID, e);
+ return nullptr;
}
void* BpBinder::ObjectManager::find(const void* objectID) const
@@ -86,9 +86,12 @@
return mObjects.valueAt(i).object;
}
-void BpBinder::ObjectManager::detach(const void* objectID)
-{
- mObjects.removeItem(objectID);
+void* BpBinder::ObjectManager::detach(const void* objectID) {
+ ssize_t idx = mObjects.indexOfKey(objectID);
+ if (idx < 0) return nullptr;
+ void* value = mObjects[idx].object;
+ mObjects.removeItemsAt(idx, 1);
+ return value;
}
void BpBinder::ObjectManager::kill()
@@ -406,14 +409,11 @@
recipient->binderDied(wp<BpBinder>::fromExisting(this));
}
-
-void BpBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
+void* BpBinder::attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) {
AutoMutex _l(mLock);
ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
- mObjects.attach(objectID, object, cleanupCookie, func);
+ return mObjects.attach(objectID, object, cleanupCookie, func);
}
void* BpBinder::findObject(const void* objectID) const
@@ -422,10 +422,14 @@
return mObjects.find(objectID);
}
-void BpBinder::detachObject(const void* objectID)
-{
+void* BpBinder::detachObject(const void* objectID) {
AutoMutex _l(mLock);
- mObjects.detach(objectID);
+ return mObjects.detach(objectID);
+}
+
+void BpBinder::withLock(const std::function<void()>& doWithLock) {
+ AutoMutex _l(mLock);
+ doWithLock();
}
BpBinder* BpBinder::remoteBinder()
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index b5eaaa3..5881703 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -34,11 +34,10 @@
using base::ScopeGuard;
-#ifdef RPC_FLAKE_PRONE
+#if RPC_FLAKE_PRONE
void rpcMaybeWaitToFlake() {
- static std::random_device r;
- static std::mutex m;
-
+ [[clang::no_destroy]] static std::random_device r;
+ [[clang::no_destroy]] static std::mutex m;
unsigned num;
{
std::lock_guard<std::mutex> lock(m);
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 8201eba..5ac0b97 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -44,7 +44,7 @@
#define RPC_FLAKE_PRONE false
-#ifdef RPC_FLAKE_PRONE
+#if RPC_FLAKE_PRONE
void rpcMaybeWaitToFlake();
#define MAYBE_WAIT_IN_FLAKE_MODE rpcMaybeWaitToFlake()
#else
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 07f5778..1c2f9b4 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -167,9 +167,12 @@
ALOGE("RpcSession::getRootObject returns nullptr");
return nullptr;
}
- binder->attachObject(kDeviceServiceExtraId,
- static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
- &cleanupCommandResult);
+
+ LOG_ALWAYS_FATAL_IF(
+ nullptr !=
+ binder->attachObject(kDeviceServiceExtraId,
+ static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
+ &cleanupCommandResult));
return binder;
}
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index b5a078c..a44c578 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -130,13 +130,13 @@
}
// The remote threw an exception. Get the message back.
- String16 message;
+ std::optional<String16> message;
status = parcel.readString16(&message);
if (status != OK) {
setFromStatusT(status);
return status;
}
- mMessage = String8(message);
+ mMessage = String8(message.value_or(String16()));
// Skip over the remote stack trace data
int32_t remote_stack_trace_header_size;
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index e04e326..269b867 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -16,10 +16,13 @@
"name": "binderDriverInterfaceTest"
},
{
+ "name": "binderHostDeviceTest"
+ },
+ {
"name": "binderTextOutputTest"
},
{
- "name": "binderParcelTest"
+ "name": "binderUnitTest"
},
{
"name": "binderLibTest"
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 472e546..46223bb 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -54,12 +54,11 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) final;
+ virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) final;
virtual void* findObject(const void* objectID) const final;
- virtual void detachObject(const void* objectID) final;
+ virtual void* detachObject(const void* objectID) final;
+ void withLock(const std::function<void()>& doWithLock);
virtual BBinder* localBinder();
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 61bf018..c69bb9e 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -72,12 +72,11 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) final;
+ virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func) final;
virtual void* findObject(const void* objectID) const final;
- virtual void detachObject(const void* objectID) final;
+ virtual void* detachObject(const void* objectID) final;
+ void withLock(const std::function<void()>& doWithLock);
virtual BpBinder* remoteBinder();
@@ -91,27 +90,23 @@
static void setLimitCallback(binder_proxy_limit_callback cb);
static void setBinderProxyCountWatermarks(int high, int low);
- class ObjectManager
- {
+ class ObjectManager {
public:
- ObjectManager();
- ~ObjectManager();
+ ObjectManager();
+ ~ObjectManager();
- void attach( const void* objectID,
- void* object,
- void* cleanupCookie,
- IBinder::object_cleanup_func func);
- void* find(const void* objectID) const;
- void detach(const void* objectID);
+ void* attach(const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func);
+ void* find(const void* objectID) const;
+ void* detach(const void* objectID);
- void kill();
+ void kill();
private:
- ObjectManager(const ObjectManager&);
+ ObjectManager(const ObjectManager&);
ObjectManager& operator=(const ObjectManager&);
- struct entry_t
- {
+ struct entry_t {
void* object;
void* cleanupCookie;
IBinder::object_cleanup_func func;
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index f9cdac7..43fc5ff 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -22,6 +22,8 @@
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <functional>
+
// linux/binder.h defines this, but we don't want to include it here in order to
// avoid exporting the kernel headers
#ifndef B_PACK_CHARS
@@ -255,26 +257,30 @@
* objects are invoked with their respective objectID, object, and
* cleanupCookie. Access to these APIs can be made from multiple threads,
* but calls from different threads are allowed to be interleaved.
+ *
+ * This returns the object which is already attached. If this returns a
+ * non-null value, it means that attachObject failed (a given objectID can
+ * only be used once).
*/
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) = 0;
+ [[nodiscard]] virtual void* attachObject(const void* objectID, void* object,
+ void* cleanupCookie, object_cleanup_func func) = 0;
/**
* Returns object attached with attachObject.
*/
- virtual void* findObject(const void* objectID) const = 0;
+ [[nodiscard]] virtual void* findObject(const void* objectID) const = 0;
/**
- * WARNING: this API does not call the cleanup function for legacy reasons.
- * It also does not return void* for legacy reasons. If you need to detach
- * an object and destroy it, there are two options:
- * - if you can, don't call detachObject and instead wait for the destructor
- * to clean it up.
- * - manually retrieve and destruct the object (if multiple of your threads
- * are accessing these APIs, you must guarantee that attachObject isn't
- * called after findObject and before detachObject is called).
+ * Returns object attached with attachObject, and detaches it. This does not
+ * delete the object.
*/
- virtual void detachObject(const void* objectID) = 0;
+ [[nodiscard]] virtual void* detachObject(const void* objectID) = 0;
+
+ /**
+ * Use the lock that this binder contains internally. For instance, this can
+ * be used to modify an attached object without needing to add an additional
+ * lock (though, that attached object must be retrieved before calling this
+ * method). Calling (most) IBinder methods inside this will deadlock.
+ */
+ void withLock(const std::function<void()>& doWithLock);
virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 9e4475c..42c85f9 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -42,6 +42,7 @@
}
mStability = other.mStability;
}
+ ParcelableHolder(ParcelableHolder&& other) = default;
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 883403a..2abb6f7 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -47,7 +47,8 @@
void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
static void attach(const sp<IBinder>& binder) {
- binder->attachObject(kId, kValue, nullptr /*cookie*/, clean);
+ // can only attach once
+ CHECK_EQ(nullptr, binder->attachObject(kId, kValue, nullptr /*cookie*/, clean));
}
static bool has(const sp<IBinder>& binder) {
return binder != nullptr && binder->findObject(kId) == kValue;
@@ -57,7 +58,6 @@
namespace ABpBinderTag {
-static std::mutex gLock;
static const void* kId = "ABpBinder";
struct Value {
wp<ABpBinder> binder;
@@ -232,19 +232,16 @@
ABpBinder::~ABpBinder() {}
void ABpBinder::onLastStrongRef(const void* id) {
- {
- std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
- // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
- // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no
- // longer be able to exist at the time of this method call, there is no longer a need to
- // recover it.
+ // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
+ // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
+ // (BpRefBase), the remote object may still exist (for instance, if we
+ // receive it from another process, before the ABpBinder is attached).
- ABpBinderTag::Value* value =
- static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
- if (value != nullptr) {
- value->binder = nullptr;
- }
- }
+ ABpBinderTag::Value* value =
+ static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
+ CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
+
+ remote()->withLock([&]() { value->binder = nullptr; });
BpRefBase::onLastStrongRef(id);
}
@@ -259,21 +256,29 @@
// The following code ensures that for a given binder object (remote or local), if it is not an
// ABBinder then at most one ABpBinder object exists in a given process representing it.
- std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
- ABpBinderTag::Value* value =
- static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
+ auto* value = static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
if (value == nullptr) {
value = new ABpBinderTag::Value;
- binder->attachObject(ABpBinderTag::kId, static_cast<void*>(value), nullptr /*cookie*/,
- ABpBinderTag::clean);
+ auto oldValue = static_cast<ABpBinderTag::Value*>(
+ binder->attachObject(ABpBinderTag::kId, static_cast<void*>(value),
+ nullptr /*cookie*/, ABpBinderTag::clean));
+
+ // allocated by another thread
+ if (oldValue) {
+ delete value;
+ value = oldValue;
+ }
}
- sp<ABpBinder> ret = value->binder.promote();
- if (ret == nullptr) {
- ret = new ABpBinder(binder);
- value->binder = ret;
- }
+ sp<ABpBinder> ret;
+ binder->withLock([&]() {
+ ret = value->binder.promote();
+ if (ret == nullptr) {
+ ret = sp<ABpBinder>::make(binder);
+ value->binder = ret;
+ }
+ });
return ret;
}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 22cacb4..f2c69b3 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -105,6 +105,7 @@
ABpBinder* asABpBinder() override { return this; }
private:
+ friend android::sp<ABpBinder>;
explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
};
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 2277148..aa3b978 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -46,7 +46,7 @@
AParcelableHolder() = delete;
explicit AParcelableHolder(parcelable_stability_t stability)
: mParcel(AParcel_create()), mStability(stability) {}
-
+ AParcelableHolder(AParcelableHolder&& other) = default;
virtual ~AParcelableHolder() = default;
binder_status_t writeToParcel(AParcel* parcel) const {
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 1c43948..5ad390e 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,6 +39,7 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
+#include <thread>
#include "android/binder_ibinder.h"
using namespace android;
@@ -250,6 +251,27 @@
EXPECT_EQ(2, out);
}
+TEST(NdkBinder, GetTestServiceStressTest) {
+ // libbinder has some complicated logic to make sure only one instance of
+ // ABpBinder is associated with each binder.
+
+ constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumCalls = 1000;
+ std::vector<std::thread> threads;
+
+ for (size_t i = 0; i < kNumThreads; i++) {
+ threads.push_back(std::thread([&]() {
+ for (size_t j = 0; j < kNumCalls; j++) {
+ auto binder =
+ ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+ }
+ }));
+ }
+
+ for (auto& thread : threads) thread.join();
+}
+
void defaultInstanceCounter(const char* instance, void* context) {
if (strcmp(instance, "default") == 0) {
++*(size_t*)(context);
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 2a09afc..dd0c7b8 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -50,7 +50,7 @@
/// interfaces) must implement this trait.
///
/// This is equivalent `IInterface` in C++.
-pub trait Interface: Send {
+pub trait Interface: Send + Sync {
/// Convert this binder object into a generic [`SpIBinder`] reference.
fn as_binder(&self) -> SpIBinder {
panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
@@ -897,7 +897,7 @@
#[macro_export]
macro_rules! declare_binder_enum {
{
- $enum:ident : $backing:ty {
+ $enum:ident : [$backing:ty; $size:expr] {
$( $name:ident = $value:expr, )*
}
} => {
@@ -905,6 +905,11 @@
pub struct $enum(pub $backing);
impl $enum {
$( pub const $name: Self = Self($value); )*
+
+ #[inline(always)]
+ pub const fn enum_values() -> [Self; $size] {
+ [$(Self::$name),*]
+ }
}
impl $crate::parcel::Serialize for $enum {
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 5e324b3..a0dfeec 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -51,6 +51,25 @@
/// to how `Box<T>` is `Send` if `T` is `Send`.
unsafe impl<T: Remotable> Send for Binder<T> {}
+/// # Safety
+///
+/// A `Binder<T>` is a pair of unique owning pointers to two values:
+/// * a C++ ABBinder which is thread-safe, i.e. `Send + Sync`
+/// * a Rust object which implements `Remotable`; this trait requires `Send + Sync`
+///
+/// `ABBinder` contains an immutable `mUserData` pointer, which is actually a
+/// pointer to a boxed `T: Remotable`, which is `Sync`. `ABBinder` also contains
+/// a mutable pointer to its class, but mutation of this field is controlled by
+/// a mutex and it is only allowed to be set once, therefore we can concurrently
+/// access this field safely. `ABBinder` inherits from `BBinder`, which is also
+/// thread-safe. Thus `ABBinder` is thread-safe.
+///
+/// Both pointers are unique (never escape the `Binder<T>` object and are not copied)
+/// so we can essentially treat `Binder<T>` as a box-like containing the two objects;
+/// the box-like object inherits `Sync` from the two inner values, similarly
+/// to how `Box<T>` is `Sync` if `T` is `Sync`.
+unsafe impl<T: Remotable> Sync for Binder<T> {}
+
impl<T: Remotable> Binder<T> {
/// Create a new Binder remotable object with default stability
///
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index e299963..cdd7c08 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -48,9 +48,14 @@
/// # Safety
///
-/// An `SpIBinder` is a handle to a C++ IBinder, which is thread-safe
+/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
unsafe impl Send for SpIBinder {}
+/// # Safety
+///
+/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+unsafe impl Sync for SpIBinder {}
+
impl SpIBinder {
/// Create an `SpIBinder` wrapper object from a raw `AIBinder` pointer.
///
@@ -448,9 +453,14 @@
/// # Safety
///
-/// A `WpIBinder` is a handle to a C++ IBinder, which is thread-safe.
+/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
unsafe impl Send for WpIBinder {}
+/// # Safety
+///
+/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+unsafe impl Sync for WpIBinder {}
+
impl WpIBinder {
/// Create a new weak reference from an object that can be converted into a
/// raw `AIBinder` pointer.
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index d5a2b61..24afcf6 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -77,14 +77,14 @@
// unit test only, which can run on host and doesn't use /dev/binder
cc_test {
- name: "binderParcelTest",
+ name: "binderUnitTest",
host_supported: true,
target: {
darwin: {
enabled: false,
},
},
- srcs: ["binderParcelTest.cpp"],
+ srcs: ["binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp"],
shared_libs: [
"libbinder",
"libutils",
@@ -348,3 +348,49 @@
},
},
}
+
+cc_test_host {
+ name: "binderHostDeviceTest",
+ defaults: ["binder_test_defaults"],
+ srcs: ["binderHostDeviceTest.cpp"],
+ test_config: "binderHostDeviceTest.xml",
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ target_required: [
+ "binderHostDeviceTestService",
+ ],
+ test_suites: ["general-tests"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ test_options: {
+ unit_test: false,
+ },
+}
+
+cc_test {
+ name: "binderHostDeviceTestService",
+ // The binary is named differently from the module so that PushFilePreparer pushes the binary
+ // directly, not the test module directory.
+ stem: "binderHostDeviceTest-service",
+ defaults: ["binder_test_defaults"],
+ gtest: false,
+ auto_gen_config: false,
+ srcs: ["binderHostDeviceTestService.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp
new file mode 100644
index 0000000..1be0c59
--- /dev/null
+++ b/libs/binder/tests/binderBinderUnitTest.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <gtest/gtest.h>
+
+using android::BBinder;
+using android::OK;
+using android::sp;
+
+const void* kObjectId1 = reinterpret_cast<const void*>(1);
+const void* kObjectId2 = reinterpret_cast<const void*>(2);
+void* kObject1 = reinterpret_cast<void*>(101);
+void* kObject2 = reinterpret_cast<void*>(102);
+void* kObject3 = reinterpret_cast<void*>(103);
+
+TEST(Binder, AttachObject) {
+ auto binder = sp<BBinder>::make();
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject1, nullptr, nullptr));
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId2, kObject2, nullptr, nullptr));
+ EXPECT_EQ(kObject1, binder->attachObject(kObjectId1, kObject3, nullptr, nullptr));
+}
+
+TEST(Binder, DetachObject) {
+ auto binder = sp<BBinder>::make();
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject1, nullptr, nullptr));
+ EXPECT_EQ(kObject1, binder->detachObject(kObjectId1));
+ EXPECT_EQ(nullptr, binder->attachObject(kObjectId1, kObject2, nullptr, nullptr));
+}
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
new file mode 100644
index 0000000..5dd9212
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Integration test for servicedispatcher + adb forward. Requires ADB.
+
+#include <stdlib.h>
+
+#include <vector>
+
+#include <android-base/parsebool.h>
+#include <android-base/result-gmock.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "../UtilsHost.h"
+
+using ::android::setDefaultServiceManager;
+using ::android::base::EndsWith;
+using ::android::base::Join;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
+using ::android::base::Split;
+using ::android::base::StartsWith;
+using ::android::base::StringReplace;
+using ::android::base::Trim;
+using ::android::base::testing::Ok;
+using ::std::chrono_literals::operator""ms;
+using ::std::string_literals::operator""s;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::ContainsRegex;
+using ::testing::ExplainMatchResult;
+using ::testing::InitGoogleMock;
+
+namespace android {
+
+namespace {
+
+constexpr const char* kServiceBinary = "/data/local/tmp/binderHostDeviceTest-service";
+constexpr const char* kServiceName = "binderHostDeviceTestService";
+constexpr const char* kDescriptor = "android.binderHostDeviceTestService";
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+ *result_listener << statusToString(arg);
+ return expected == arg;
+}
+
+void initHostRpcServiceManagerOnce() {
+ static std::once_flag gSmOnce;
+ std::call_once(gSmOnce, [] { setDefaultServiceManager(createRpcDelegateServiceManager()); });
+}
+
+// Test for host service manager.
+class HostDeviceTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ auto debuggableResult = execute(Split("adb shell getprop ro.debuggable", " "), nullptr);
+ ASSERT_THAT(debuggableResult, Ok());
+ ASSERT_EQ(0, debuggableResult->exitCode) << *debuggableResult;
+ auto debuggableBool = ParseBool(Trim(debuggableResult->stdout));
+ ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdout);
+ if (debuggableBool == ParseBoolResult::kFalse) {
+ GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdout);
+ }
+
+ auto lsResult = execute(Split("adb shell which servicedispatcher", " "), nullptr);
+ ASSERT_THAT(lsResult, Ok());
+ if (lsResult->exitCode != 0) {
+ GTEST_SKIP() << "b/182914638: until feature is fully enabled, skip test on devices "
+ "without servicedispatcher";
+ }
+
+ initHostRpcServiceManagerOnce();
+ ASSERT_NE(nullptr, defaultServiceManager()) << "No defaultServiceManager() over RPC";
+
+ auto service = execute({"adb", "shell", kServiceBinary, kServiceName, kDescriptor},
+ &CommandResult::stdoutEndsWithNewLine);
+ ASSERT_THAT(service, Ok());
+ ASSERT_EQ(std::nullopt, service->exitCode) << *service;
+ mService = std::move(*service);
+ }
+ void TearDown() override { mService.reset(); }
+
+ [[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
+ auto rpcSession = RpcSession::make();
+ if (!rpcSession->setupInetClient("127.0.0.1", hostPort)) {
+ ADD_FAILURE() << "Failed to setupInetClient on " << hostPort;
+ return nullptr;
+ }
+ return rpcSession->getRootObject();
+ }
+
+private:
+ std::optional<CommandResult> mService;
+};
+
+TEST_F(HostDeviceTest, List) {
+ auto sm = defaultServiceManager();
+
+ auto services = sm->listServices();
+ ASSERT_THAT(services, Contains(String16(kServiceName)));
+}
+
+TEST_F(HostDeviceTest, CheckService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->checkService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, GetService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->getService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, WaitForService) {
+ auto sm = defaultServiceManager();
+
+ auto rpcBinder = sm->waitForService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, TenClients) {
+ auto sm = defaultServiceManager();
+
+ auto threadFn = [&] {
+ auto rpcBinder = sm->checkService(String16(kServiceName));
+ ASSERT_NE(nullptr, rpcBinder);
+
+ EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+ EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+ };
+
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < 10; ++i) threads.emplace_back(threadFn);
+ for (auto& thread : threads) thread.join();
+}
+
+} // namespace
+
+} // namespace android
diff --git a/libs/binder/tests/binderHostDeviceTest.xml b/libs/binder/tests/binderHostDeviceTest.xml
new file mode 100644
index 0000000..250ed3a
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs binderHostDeviceTest.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push-file" key="binderHostDeviceTest-service"
+ value="/data/local/tmp/binderHostDeviceTest-service"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest">
+ <option name="binary" value="binderHostDeviceTest"/>
+ </test>
+</configuration>
diff --git a/libs/binder/tests/binderHostDeviceTestService.cpp b/libs/binder/tests/binderHostDeviceTestService.cpp
new file mode 100644
index 0000000..6ddd2e7
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTestService.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sysexits.h>
+
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+namespace {
+class Service : public android::BBinder {
+public:
+ Service(std::string_view descriptor) : mDescriptor(descriptor.data(), descriptor.size()) {}
+ const android::String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+private:
+ android::String16 mDescriptor;
+};
+} // namespace
+
+int main(int argc, char** argv) {
+ if (argc != 3) {
+ std::cerr << "usage: " << argv[0] << " <service-name> <interface-descriptor>" << std::endl;
+ return EX_USAGE;
+ }
+ auto name = argv[1];
+ auto descriptor = argv[2];
+
+ auto sm = android::defaultServiceManager();
+ CHECK(sm != nullptr);
+ auto service = android::sp<Service>::make(descriptor);
+ auto status = sm->addService(android::String16(name), service);
+ CHECK_EQ(android::OK, status) << android::statusToString(status);
+ std::cout << "running..." << std::endl;
+ android::ProcessState::self()->startThreadPool();
+ android::IPCThreadState::self()->joinThreadPool();
+ LOG(ERROR) << "joinThreadPool exits";
+ return EX_SOFTWARE;
+}
diff --git a/libs/binder/tests/binderParcelTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
similarity index 65%
rename from libs/binder/tests/binderParcelTest.cpp
rename to libs/binder/tests/binderParcelUnitTest.cpp
index 1764228..fb49d7a 100644
--- a/libs/binder/tests/binderParcelTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
#include <gtest/gtest.h>
using android::IPCThreadState;
using android::OK;
using android::Parcel;
+using android::status_t;
using android::String16;
using android::String8;
-using android::status_t;
// Tests a second operation results in a parcel at the same location as it
// started.
-void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
+void parcelOpSameLength(const std::function<void(Parcel*)>& a,
+ const std::function<void(Parcel*)>& b) {
Parcel p;
a(&p);
size_t end = p.dataPosition();
@@ -38,33 +39,30 @@
TEST(Parcel, InverseInterfaceToken) {
const String16 token = String16("asdf");
- parcelOpSameLength([&] (Parcel* p) {
- p->writeInterfaceToken(token);
- }, [&] (Parcel* p) {
- EXPECT_TRUE(p->enforceInterface(token, IPCThreadState::self()));
- });
+ parcelOpSameLength([&](Parcel* p) { p->writeInterfaceToken(token); },
+ [&](Parcel* p) {
+ EXPECT_TRUE(p->enforceInterface(token, IPCThreadState::self()));
+ });
}
TEST(Parcel, Utf8FromUtf16Read) {
const char* token = "asdf";
- parcelOpSameLength([&] (Parcel* p) {
- p->writeString16(String16(token));
- }, [&] (Parcel* p) {
- std::string s;
- EXPECT_EQ(OK, p->readUtf8FromUtf16(&s));
- EXPECT_EQ(token, s);
- });
+ parcelOpSameLength([&](Parcel* p) { p->writeString16(String16(token)); },
+ [&](Parcel* p) {
+ std::string s;
+ EXPECT_EQ(OK, p->readUtf8FromUtf16(&s));
+ EXPECT_EQ(token, s);
+ });
}
TEST(Parcel, Utf8AsUtf16Write) {
std::string token = "asdf";
- parcelOpSameLength([&] (Parcel* p) {
- p->writeUtf8AsUtf16(token);
- }, [&] (Parcel* p) {
- String16 s;
- EXPECT_EQ(OK, p->readString16(&s));
- EXPECT_EQ(s, String16(token.c_str()));
- });
+ parcelOpSameLength([&](Parcel* p) { p->writeUtf8AsUtf16(token); },
+ [&](Parcel* p) {
+ String16 s;
+ EXPECT_EQ(OK, p->readString16(&s));
+ EXPECT_EQ(s, String16(token.c_str()));
+ });
}
template <typename T>
@@ -77,13 +75,12 @@
template <typename T, typename WRITE_FUNC>
void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, WRITE_FUNC w) {
for (const T& value : ts) {
- parcelOpSameLength([&] (Parcel* p) {
- (*p.*w)(value);
- }, [&] (Parcel* p) {
- T outValue;
- EXPECT_EQ(OK, (*p.*r)(&outValue));
- EXPECT_EQ(value, outValue);
- });
+ parcelOpSameLength([&](Parcel* p) { (*p.*w)(value); },
+ [&](Parcel* p) {
+ T outValue;
+ EXPECT_EQ(OK, (*p.*r)(&outValue));
+ EXPECT_EQ(value, outValue);
+ });
}
}
@@ -96,8 +93,8 @@
readWriteInverse<T, copyWriteFunc<T>>(std::move(ts), r, w);
}
-#define TEST_READ_WRITE_INVERSE(type, name, ...) \
- TEST(Parcel, Inverse##name) { \
+#define TEST_READ_WRITE_INVERSE(type, name, ...) \
+ TEST(Parcel, Inverse##name) { \
readWriteInverse<type>(__VA_ARGS__, &Parcel::read##name, &Parcel::write##name); \
}
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 626b758..4a0aeba 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -62,20 +62,22 @@
object = fdp->ConsumeIntegral<uint32_t>();
cleanup_cookie = fdp->ConsumeIntegral<uint32_t>();
IBinder::object_cleanup_func func = IBinder::object_cleanup_func();
- ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
- : nullptr,
- fdp->ConsumeBool() ? reinterpret_cast<void*>(&object) : nullptr,
- fdp->ConsumeBool() ? reinterpret_cast<void*>(&cleanup_cookie)
- : nullptr,
- func);
+ (void)ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
+ : nullptr,
+ fdp->ConsumeBool() ? reinterpret_cast<void*>(&object)
+ : nullptr,
+ fdp->ConsumeBool()
+ ? reinterpret_cast<void*>(&cleanup_cookie)
+ : nullptr,
+ func);
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t id = fdp->ConsumeIntegral<uint32_t>();
- ibinder->findObject(reinterpret_cast<void*>(&id));
+ (void)ibinder->findObject(reinterpret_cast<void*>(&id));
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t id = fdp->ConsumeIntegral<uint32_t>();
- ibinder->detachObject(reinterpret_cast<void*>(&id));
+ (void)ibinder->detachObject(reinterpret_cast<void*>(&id));
},
[](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
uint32_t code = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 3030068..ccc47e9 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -643,6 +643,8 @@
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
return 4;
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ return 8;
default:
return 0;
}
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
index c75213b..16e1e8a 100644
--- a/services/gpuservice/bpfprogs/gpu_mem.c
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -72,4 +72,4 @@
return 0;
}
-char _license[] SEC("license") = "Apache 2.0";
+LICENSE("Apache 2.0");
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index dadbd0e..9846640 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -90,4 +90,7 @@
export_header_lib_headers: [
"libinputreader_headers",
],
+ static_libs: [
+ "libc++fs"
+ ],
}
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index a1514af..20a843f 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -34,20 +34,20 @@
#define LOG_TAG "EventHub"
// #define LOG_NDEBUG 0
-
-#include "EventHub.h"
-
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/VirtualKeyMap.h>
#include <openssl/sha.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/threads.h>
-#include <input/KeyCharacterMap.h>
-#include <input/KeyLayoutMap.h>
-#include <input/VirtualKeyMap.h>
+#include <filesystem>
+
+#include "EventHub.h"
/* this macro is used to tell if "bit" is set in "array"
* it selects a byte from the array, and does a boolean AND
@@ -69,9 +69,9 @@
static constexpr bool DEBUG = false;
-static const char* DEVICE_PATH = "/dev/input";
+static const char* DEVICE_INPUT_PATH = "/dev/input";
// v4l2 devices go directly into /dev
-static const char* VIDEO_DEVICE_PATH = "/dev";
+static const char* DEVICE_PATH = "/dev";
static inline const char* toString(bool value) {
return value ? "true" : "false";
@@ -94,8 +94,8 @@
/**
* Return true if name matches "v4l-touch*"
*/
-static bool isV4lTouchNode(const char* name) {
- return strstr(name, "v4l-touch") == name;
+static bool isV4lTouchNode(std::string name) {
+ return name.find("v4l-touch") != std::string::npos;
}
/**
@@ -298,15 +298,23 @@
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
mINotifyFd = inotify_init();
- mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
- strerror(errno));
- if (isV4lScanningEnabled()) {
- mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
- VIDEO_DEVICE_PATH, strerror(errno));
+
+ std::error_code errorCode;
+ bool isDeviceInotifyAdded = false;
+ if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+ addDeviceInputInotify();
} else {
- mVideoWd = -1;
+ addDeviceInotify();
+ isDeviceInotifyAdded = true;
+ if (errorCode) {
+ ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+ errorCode.message().c_str());
+ }
+ }
+
+ if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
+ addDeviceInotify();
+ } else {
ALOGI("Video device scanning disabled");
}
@@ -352,6 +360,23 @@
::close(mWakeWritePipeFd);
}
+/**
+ * On devices that don't have any input devices (like some development boards), the /dev/input
+ * directory will be absent. However, the user may still plug in an input device at a later time.
+ * Add watch for contents of /dev/input only when /dev/input appears.
+ */
+void EventHub::addDeviceInputInotify() {
+ mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mDeviceInputWd < 0, "Could not register INotify for %s: %s",
+ DEVICE_INPUT_PATH, strerror(errno));
+}
+
+void EventHub::addDeviceInotify() {
+ mDeviceWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mDeviceWd < 0, "Could not register INotify for %s: %s",
+ DEVICE_PATH, strerror(errno));
+}
+
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
@@ -810,7 +835,7 @@
return index >= 0 ? mDevices.valueAt(index) : NULL;
}
-EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const {
+EventHub::Device* EventHub::getDeviceByPathLocked(const std::string& devicePath) const {
for (size_t i = 0; i < mDevices.size(); i++) {
Device* device = mDevices.valueAt(i);
if (device->path == devicePath) {
@@ -1109,14 +1134,24 @@
}
void EventHub::scanDevicesLocked() {
- status_t result = scanDirLocked(DEVICE_PATH);
- if (result < 0) {
- ALOGE("scan dir failed for %s", DEVICE_PATH);
+ status_t result;
+ std::error_code errorCode;
+
+ if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+ result = scanDirLocked(DEVICE_INPUT_PATH);
+ if (result < 0) {
+ ALOGE("scan dir failed for %s", DEVICE_INPUT_PATH);
+ }
+ } else {
+ if (errorCode) {
+ ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+ errorCode.message().c_str());
+ }
}
if (isV4lScanningEnabled()) {
- result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+ result = scanVideoDirLocked(DEVICE_PATH);
if (result != OK) {
- ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+ ALOGE("scan video dir failed for %s", DEVICE_PATH);
}
}
if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
@@ -1215,14 +1250,14 @@
}
}
-status_t EventHub::openDeviceLocked(const char* devicePath) {
+status_t EventHub::openDeviceLocked(const std::string& devicePath) {
char buffer[80];
- ALOGV("Opening device: %s", devicePath);
+ ALOGV("Opening device: %s", devicePath.c_str());
- int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
if (fd < 0) {
- ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
+ ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));
return -1;
}
@@ -1230,7 +1265,7 @@
// Get device name.
if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
- ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
+ ALOGE("Could not get device name for %s: %s", devicePath.c_str(), strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name = buffer;
@@ -1240,7 +1275,7 @@
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
const std::string& item = mExcludedDevices[i];
if (identifier.name == item) {
- ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
+ ALOGI("ignoring event id %s driver %s\n", devicePath.c_str(), item.c_str());
close(fd);
return -1;
}
@@ -1249,7 +1284,7 @@
// Get device driver version.
int driverVersion;
if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
- ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
+ ALOGE("could not get driver version for %s, %s\n", devicePath.c_str(), strerror(errno));
close(fd);
return -1;
}
@@ -1257,7 +1292,7 @@
// Get device identifier.
struct input_id inputId;
if (ioctl(fd, EVIOCGID, &inputId)) {
- ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
+ ALOGE("could not get device input id for %s, %s\n", devicePath.c_str(), strerror(errno));
close(fd);
return -1;
}
@@ -1289,7 +1324,7 @@
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, devicePath, identifier);
- ALOGV("add device %d: %s\n", deviceId, devicePath);
+ ALOGV("add device %d: %s\n", deviceId, devicePath.c_str());
ALOGV(" bus: %04x\n"
" vendor %04x\n"
" product %04x\n"
@@ -1446,7 +1481,7 @@
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
- ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath,
+ ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
device->identifier.name.c_str());
delete device;
return -1;
@@ -1492,7 +1527,7 @@
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
- deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes,
+ deviceId, fd, devicePath.c_str(), device->identifier.name.c_str(), device->classes,
device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(),
device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId));
@@ -1724,13 +1759,13 @@
return NAME_NOT_FOUND;
}
-void EventHub::closeDeviceByPathLocked(const char* devicePath) {
+void EventHub::closeDeviceByPathLocked(const std::string& devicePath) {
Device* device = getDeviceByPathLocked(devicePath);
if (device) {
closeDeviceLocked(device);
return;
}
- ALOGV("Remove device: %s not found, device may already have been removed.", devicePath);
+ ALOGV("Remove device: %s not found, device may already have been removed.", devicePath.c_str());
}
/**
@@ -1834,23 +1869,25 @@
while (res >= (int)sizeof(*event)) {
event = (struct inotify_event*)(event_buf + event_pos);
if (event->len) {
- if (event->wd == mInputWd) {
- std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
+ if (event->wd == mDeviceInputWd) {
+ std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name;
if (event->mask & IN_CREATE) {
- openDeviceLocked(filename.c_str());
+ openDeviceLocked(filename);
} else {
ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
- closeDeviceByPathLocked(filename.c_str());
+ closeDeviceByPathLocked(filename);
}
- } else if (event->wd == mVideoWd) {
+ } else if (event->wd == mDeviceWd) {
if (isV4lTouchNode(event->name)) {
- std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name);
+ std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
if (event->mask & IN_CREATE) {
openVideoDeviceLocked(filename);
} else {
ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
closeVideoDeviceByPathLocked(filename);
}
+ } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE ) {
+ addDeviceInputInotify();
}
} else {
LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
@@ -1863,24 +1900,10 @@
return 0;
}
-status_t EventHub::scanDirLocked(const char* dirname) {
- char devname[PATH_MAX];
- char* filename;
- DIR* dir;
- struct dirent* de;
- dir = opendir(dirname);
- if (dir == nullptr) return -1;
- strcpy(devname, dirname);
- filename = devname + strlen(devname);
- *filename++ = '/';
- while ((de = readdir(dir))) {
- if (de->d_name[0] == '.' &&
- (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
- continue;
- strcpy(filename, de->d_name);
- openDeviceLocked(devname);
+status_t EventHub::scanDirLocked(const std::string& dirname) {
+ for (const auto& entry : std::filesystem::directory_iterator(dirname)) {
+ openDeviceLocked(entry.path());
}
- closedir(dir);
return 0;
}
@@ -1888,22 +1911,12 @@
* Look for all dirname/v4l-touch* devices, and open them.
*/
status_t EventHub::scanVideoDirLocked(const std::string& dirname) {
- DIR* dir;
- struct dirent* de;
- dir = opendir(dirname.c_str());
- if (!dir) {
- ALOGE("Could not open video directory %s", dirname.c_str());
- return BAD_VALUE;
- }
-
- while ((de = readdir(dir))) {
- const char* name = de->d_name;
- if (isV4lTouchNode(name)) {
- ALOGI("Found touch video device %s", name);
- openVideoDeviceLocked(dirname + "/" + name);
+ for (const auto& entry : std::filesystem::directory_iterator(dirname)) {
+ if (isV4lTouchNode(entry.path())) {
+ ALOGI("Found touch video device %s", entry.path().c_str());
+ openVideoDeviceLocked(entry.path());
}
}
- closedir(dir);
return OK;
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index f5451d7..55f658e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -373,13 +373,13 @@
}
};
- status_t openDeviceLocked(const char* devicePath);
+ status_t openDeviceLocked(const std::string& devicePath);
void openVideoDeviceLocked(const std::string& devicePath);
void createVirtualKeyboardLocked();
void addDeviceLocked(Device* device);
void assignDescriptorLocked(InputDeviceIdentifier& identifier);
- void closeDeviceByPathLocked(const char* devicePath);
+ void closeDeviceByPathLocked(const std::string& devicePath);
void closeVideoDeviceByPathLocked(const std::string& devicePath);
void closeDeviceLocked(Device* device);
void closeAllDevicesLocked();
@@ -396,14 +396,14 @@
status_t unregisterDeviceFromEpollLocked(Device* device);
void unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice);
- status_t scanDirLocked(const char* dirname);
+ status_t scanDirLocked(const std::string& dirname);
status_t scanVideoDirLocked(const std::string& dirname);
void scanDevicesLocked();
status_t readNotifyLocked();
Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
Device* getDeviceLocked(int32_t deviceId) const;
- Device* getDeviceByPathLocked(const char* devicePath) const;
+ Device* getDeviceByPathLocked(const std::string& devicePath) const;
/**
* Look through all available fd's (both for input devices and for video devices),
* and return the device pointer.
@@ -426,6 +426,9 @@
status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const;
void setLedStateLocked(Device* device, int32_t led, bool on);
+ void addDeviceInputInotify();
+ void addDeviceInotify();
+
// Protect all internal state.
mutable Mutex mLock;
@@ -465,8 +468,8 @@
int mWakeReadPipeFd;
int mWakeWritePipeFd;
- int mInputWd;
- int mVideoWd;
+ int mDeviceInputWd;
+ int mDeviceWd = -1;
// Maximum number of signalled FDs to handle at a time.
static const int EPOLL_MAX_EVENTS = 16;
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 86ed60d..24a27cf 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -46,5 +46,8 @@
"InputReader_test.cpp",
"UinputDevice.cpp",
],
+ static_libs: [
+ "libc++fs"
+ ],
require_root: true,
}
diff --git a/vulkan/README.md b/vulkan/README.md
index 185aa39..144805c 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -14,7 +14,7 @@
## Code Generation
-We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
+We generate several parts of the loader and tools directly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
### Run The Code Generator