1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ANDROID_BINDER_H_
#define BASE_ANDROID_BINDER_H_
#include <android/binder_ibinder.h>
#include <android/binder_parcel.h>
#include <android/binder_status.h>
#include <jni.h>
#include <cstdint>
#include <type_traits>
#include <utility>
#include <vector>
#include "base/android/scoped_java_ref.h"
#include "base/base_export.h"
#include "base/check.h"
#include "base/containers/span.h"
#include "base/files/scoped_file.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/numerics/safe_conversions.h"
#include "base/synchronization/lock.h"
#include "base/types/expected.h"
#include "base/types/expected_macros.h"
// DEFINE_BINDER_CLASS() generates a definition for a unique binder class.
// Binder classes are used by the binder implementation to enforce a kind of
// type safety, requiring client IBinders to be associated with the same class
// as the remote object's original IBinder.
//
// Objects implementing SupportsBinder<T> must specify such a class as the T;
// and clients wishing to perform transactions against such objects must use a
// TypedBinderRef<T> to do so.
//
// See usage comments on SupportsBinder<T> below.
#define _BINDER_CLASS_LINE(line) _BINDER_CLASS_LINE2(line)
#define _BINDER_CLASS_LINE2(line) #line
#define DEFINE_BINDER_CLASS(name) \
struct name : public base::android::internal::BinderClassBase { \
using BinderRef = base::android::TypedBinderRef<name>; \
static inline AIBinder_Class* GetBinderClass() { \
static AIBinder_Class* const clazz = RegisterBinderClass( \
#name ":" __FILE__ ":" _BINDER_CLASS_LINE(__LINE__)); \
return clazz; \
} \
static inline base::android::TypedBinderRef<name> AdoptBinderRef( \
base::android::BinderRef binder) { \
return base::android::TypedBinderRef<name>::Adopt(std::move(binder)); \
} \
}
namespace base::android {
class BinderRef;
class Parcel;
template <typename T>
using BinderStatusOr = expected<T, binder_status_t>;
// Provides a read-only view into a AParcel. Does not retain ownership of the
// AParcel, which must outlive this object.
class BASE_EXPORT ParcelReader {
public:
explicit ParcelReader(const AParcel* parcel);
explicit ParcelReader(const Parcel& parcel);
ParcelReader(const ParcelReader&);
ParcelReader& operator=(const ParcelReader&);
~ParcelReader();
// A subset of the NDK functions defined for reading from an AParcel. Others
// may be exposed here as needed.
BinderStatusOr<BinderRef> ReadBinder() const;
BinderStatusOr<int32_t> ReadInt32() const;
BinderStatusOr<uint32_t> ReadUint32() const;
BinderStatusOr<uint64_t> ReadUint64() const;
BinderStatusOr<ScopedFD> ReadFileDescriptor() const;
// Reads a byte array from the parcel. `allocator` is called with a single
// size_t argument for the number of bytes in the array and must return a
// pointer to at least that much memory, into which ReadByteArray() will copy
// the array data before returning. If the parcel contains an empty or null
// byte array, `allocator` is not invoked. If `allocator` is invoked and
// returns null, ReadByteArray() returns an error.
template <typename Allocator>
BinderStatusOr<void> ReadByteArray(Allocator allocator) const {
auto c_allocator = [](void* context, int32_t length, int8_t** out) {
const auto& allocator = *static_cast<Allocator*>(context);
const auto size = saturated_cast<size_t>(length);
if (!size) {
*out = nullptr;
return true;
}
// Binder API wants int8_t for bytes, but we generally use uint8_t.
uint8_t* const data = allocator(size);
*out = reinterpret_cast<int8_t*>(data);
return !!data;
};
return ReadByteArrayImpl(c_allocator, &allocator);
}
private:
BinderStatusOr<void> ReadByteArrayImpl(AParcel_byteArrayAllocator allocator,
void* context) const;
raw_ptr<const AParcel> parcel_;
};
// Provides a writable view into a AParcel. Does not retain ownership of the
// AParcel, which must outlive this object.
class BASE_EXPORT ParcelWriter {
public:
explicit ParcelWriter(AParcel* parcel);
explicit ParcelWriter(Parcel& parcel);
ParcelWriter(const ParcelWriter&);
ParcelWriter& operator=(const ParcelWriter&);
~ParcelWriter();
// A subset of the NDK functions defined for writing to an AParcel. Others may
// be exposed here as needed.
BinderStatusOr<void> WriteBinder(BinderRef binder) const;
BinderStatusOr<void> WriteInt32(int32_t value) const;
BinderStatusOr<void> WriteUint32(uint32_t value) const;
BinderStatusOr<void> WriteUint64(uint64_t value) const;
BinderStatusOr<void> WriteByteArray(span<const uint8_t> bytes) const;
BinderStatusOr<void> WriteFileDescriptor(ScopedFD fd) const;
private:
raw_ptr<AParcel> parcel_;
};
// Wraps unique ownership of an AParcel. This is similar to the NDK's
// ScopedAParcel, but it uses our internal BinderApi to invoke NDK functions.
class BASE_EXPORT Parcel {
public:
Parcel();
explicit Parcel(AParcel* parcel);
Parcel(Parcel&& other);
Parcel& operator=(Parcel&& other);
~Parcel();
explicit operator bool() const { return parcel_ != nullptr; }
const AParcel* get() const { return parcel_; }
AParcel* get() { return parcel_; }
[[nodiscard]] AParcel* release() { return std::exchange(parcel_, nullptr); }
void reset();
ParcelReader reader() const { return ParcelReader(*this); }
ParcelWriter writer() { return ParcelWriter(*this); }
private:
raw_ptr<AParcel> parcel_ = nullptr;
};
// A BinderRef owns a strong ref-count on an AIBinder. This is like the NDK's
// SpAIBinder, but it uses our internal BinderApi to invoke NDK functions.
class BASE_EXPORT BinderRef {
public:
BinderRef();
explicit BinderRef(AIBinder* binder);
BinderRef(const BinderRef& other);
BinderRef& operator=(const BinderRef& other);
BinderRef(BinderRef&& other);
BinderRef& operator=(BinderRef&& other);
~BinderRef();
explicit operator bool() const { return binder_ != nullptr; }
AIBinder* get() const { return binder_; }
[[nodiscard]] AIBinder* release() { return std::exchange(binder_, nullptr); }
void reset();
// Returns a new strong reference to this binder as a local Java object
// reference.
ScopedJavaLocalRef<jobject> ToJavaBinder(JNIEnv* env) const;
// Returns a new strong reference to an existing Java binder as a BinderRef.
static BinderRef FromJavaBinder(JNIEnv* env, jobject java_binder);
// Attempts to associate this binder with `binder_class`. Generally should be
// used via TypedBinderRef<T>::Adopt() or the equivalent T::AdoptBinderRef()
// for some binder class T.
bool AssociateWithClass(AIBinder_Class* binder_class);
protected:
// Protected to force usage through a strongly typed subclass, ensuring that
// transaction clients have an associated binder class. See documentation on
// TypedBinderRef<T> below.
BinderStatusOr<Parcel> PrepareTransaction();
BinderStatusOr<Parcel> TransactImpl(transaction_code_t code,
Parcel parcel,
binder_flags_t flags);
protected:
raw_ptr<AIBinder> binder_ = nullptr;
};
namespace internal {
// Base class for classes generated by DEFINE_BINDER_CLASS().
class BASE_EXPORT BinderClassBase {
public:
static AIBinder_Class* RegisterBinderClass(const char* descriptor);
};
// Common implementation for SupportsBinder<T> below. Instances of this base
// class handle IBinder callbacks and forward events for destruction and
// incoming transactions to a templated subclass.
class BASE_EXPORT SupportsBinderBase
: public RefCountedThreadSafe<SupportsBinderBase> {
public:
explicit SupportsBinderBase(AIBinder_Class* binder_class);
// Called for every incoming transaction on the underlying IBinder. Note that
// this is called from the binder thread pool so implementations must be
// thread-safe.
virtual BinderStatusOr<void> OnBinderTransaction(transaction_code_t code,
const ParcelReader& in,
const ParcelWriter& out) = 0;
// Called any time the underlying IBinder is destroyed. Note that this may be
// invoked multiple times, as the underlying IBinder exists only as long as
// there are living BinderRefs referencing this object. If BinderRefs are
// created and then all destroyed, this will be invoked once. If subsequent
// BinderRefs are created and then all destroyed, this will be invoked again.
//
// Similar to OnBinderTransaction, this is invoked from the binder thread pool
// and implementations must be thread-safe.
virtual void OnBinderDestroyed();
protected:
friend class RefCountedThreadSafe<SupportsBinderBase>;
friend class BinderClassBase;
virtual ~SupportsBinderBase();
// Creates a strong reference to the underlying IBinder, allocating a new
// IBinder if one did not already exist for this object.
BinderRef GetBinder();
private:
void OnBinderDestroyedBase();
// Binder class callbacks.
static void* OnIBinderCreate(void* self);
static void OnIBinderDestroy(void* self);
static binder_status_t OnIBinderTransact(AIBinder* binder,
transaction_code_t code,
const AParcel* in,
AParcel* out);
const raw_ptr<AIBinder_Class> binder_class_;
Lock lock_;
// A weak reference to the underlying IBinder, if one exists.
raw_ptr<AIBinder_Weak> weak_binder_ GUARDED_BY(lock_) = nullptr;
// As long as any IBinder is alive for this object, we retain an extra ref
// count on `this` to ensure that transactions can be handled safely.
scoped_refptr<SupportsBinderBase> self_for_binder_ GUARDED_BY(lock_);
};
} // namespace internal
// A BinderRef which has been associated with a specific binder class.
template <typename T>
class TypedBinderRef : public BinderRef {
public:
static_assert(std::is_base_of_v<android::internal::BinderClassBase, T>,
"Invalid binder class type");
TypedBinderRef() = default;
// Asserts that the binder can be associated with class T. This is safe to
// call when it's known that the binder hasn't been associated with any other
// class in the calling process yet.
explicit TypedBinderRef(BinderRef binder) {
CHECK(!binder || binder.AssociateWithClass(T::GetBinderClass()));
binder_ = binder.release();
}
TypedBinderRef(const TypedBinderRef&) = default;
TypedBinderRef& operator=(const TypedBinderRef&) = default;
TypedBinderRef(TypedBinderRef&&) = default;
TypedBinderRef& operator=(TypedBinderRef&&) = default;
~TypedBinderRef() = default;
// Adopts a BinderRef that is not already associated with another binder
// class, associating it with T. If `binder` is already associated with T this
// is a no-op which only narrows the ref type.
//
// If `binder` was already associated with a binder class other than T, the
// reference is dropped and this returns null.
//
// For convenience clients may instead prefer to call this method via
// T::AdoptBinderRef() as defined by DEFINE_BINDER_CLASS(T).
static TypedBinderRef<T> Adopt(BinderRef binder) {
TypedBinderRef<T> typed_binder;
if (binder.AssociateWithClass(T::GetBinderClass())) {
typed_binder.binder_ = binder.release();
}
return typed_binder;
}
// Prepares a new transaction on this binder, returning a Parcel that can be
// populated and then sent via Transact() or TransactOneWay() below.
BinderStatusOr<Parcel> PrepareTransaction() {
return BinderRef::PrepareTransaction();
}
// Transact with a `parcel` created by a call to PrepareTransaction() on the
// same binder. Returns the output parcel from the transaction. `code` is
// an arbitrary value with interface-specific meaning.
BinderStatusOr<Parcel> Transact(transaction_code_t code, Parcel parcel) {
return TransactImpl(code, std::move(parcel), /*flags=*/0);
}
// Like Transact(), but this internally prepares a transacation and passes the
// allocated Parcel into `fn`. After `fn` returns the Parcel is transacted.
template <typename Fn>
BinderStatusOr<Parcel> Transact(transaction_code_t code, Fn fn) {
ASSIGN_OR_RETURN(auto parcel, PrepareTransaction());
RETURN_IF_ERROR(fn(ParcelWriter(parcel.get())));
return Transact(code, std::move(parcel));
}
// Like Transact() but asynchronous. Discards the empty response parcel.
BinderStatusOr<void> TransactOneWay(transaction_code_t code, Parcel parcel) {
RETURN_IF_ERROR(TransactImpl(code, std::move(parcel), FLAG_ONEWAY));
return ok();
}
// Like TransactOneWay(), but this internally prepares a transaction
// passes the allocated Parcel into `fn`. After `fn` returns the Parcel is
// transacted.
template <typename Fn>
BinderStatusOr<void> TransactOneWay(transaction_code_t code, Fn fn) {
ASSIGN_OR_RETURN(auto parcel, PrepareTransaction());
RETURN_IF_ERROR(fn(ParcelWriter(parcel.get())));
return TransactOneWay(code, std::move(parcel));
}
};
// Base class for objects which support native binder transactions. Example
// usage:
//
// // In some common header.
// DEFINE_BINDER_CLASS(ThingyInterface);
//
// // The interface implementation.
// class Thingy : public base::android::SupportsBinder<ThingyInterface> {
// public:
// ... (normal class stuff, plus overrides of SupportsBinder methods)
// };
//
// // The client. `ref` generally comes from the parent process untyped,
// // specifically from some SupportsBinder<T> subclass calling GetBinder().
// void UseThingy(BinderRef ref) {
// auto thingy = ThingyInterface::AdoptBinderRef(std::move(ref));
// ... (do transactions with `thingy`)
// }
template <typename T>
class BASE_EXPORT SupportsBinder : public internal::SupportsBinderBase {
public:
static_assert(std::is_base_of_v<android::internal::BinderClassBase, T>,
"Invalid binder class type");
SupportsBinder() : SupportsBinderBase(T::GetBinderClass()) {}
// Creates a strong reference to the underlying IBinder, allocating a new
// IBinder if one did not already exist for this object.
TypedBinderRef<T> GetBinder() {
return TypedBinderRef<T>(SupportsBinderBase::GetBinder());
}
protected:
~SupportsBinder() override = default;
};
// Indicates whether Binder NDK functionality is generally available to the
// caller. If this returns false, BinderRefs will always be null and
// SupportsBinder<T> implementations will never receive binder transactions; but
// definitions within this header are otherwise still safe to reference and use.
BASE_EXPORT bool IsNativeBinderAvailable();
// Stashes a global collection of BinderRefs for later retrieval by
// TakeBinderFromParent(). This is intended for use by generic multiprocess
// support code to retain interfaces from the parent process so application-
// specific logic in the child process can retrieve them later. It should be
// called at most once per process, and as early as possible.
BASE_EXPORT void SetBindersFromParent(std::vector<BinderRef> binders);
// Retrieves (by index) a BinderRef which was stashed earlier by
// SetBindersFromParent(). If there is no binder for the given index, the
// returned BinderRef is null. This consumes the binder for that index, so
// subsequent calls for the same index will always return null.
BASE_EXPORT BinderRef TakeBinderFromParent(size_t index);
} // namespace base::android
#endif // BASE_ANDROID_BINDER_H_
|