1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/android/binder_box.h"
6
7 #include <android/binder_ibinder.h>
8 #include <jni.h>
9
10 #include <cstddef>
11 #include <utility>
12 #include <vector>
13
14 #include "base/android/binder.h"
15 #include "base/android/scoped_java_ref.h"
16 #include "base/types/expected_macros.h"
17
18 namespace base::android {
19
20 namespace {
21
22 DEFINE_BINDER_CLASS(BinderBoxInterface);
23
24 // Binder transaction support for PackBinderBox() and UnpackBinderBox().
25 class BinderBox : public SupportsBinder<BinderBoxInterface> {
26 static constexpr transaction_code_t kUnpack = 1;
27
28 public:
BinderBox(std::vector<BinderRef> binders)29 explicit BinderBox(std::vector<BinderRef> binders)
30 : binders_(std::move(binders)) {}
31
GetJavaBinder(JNIEnv * env)32 ScopedJavaLocalRef<jobject> GetJavaBinder(JNIEnv* env) {
33 return GetBinder().ToJavaBinder(env);
34 }
35
Unpack(JNIEnv * env,const JavaRef<jobject> & box)36 static BinderStatusOr<std::vector<BinderRef>> Unpack(
37 JNIEnv* env,
38 const JavaRef<jobject>& box) {
39 auto proxy = TypedBinderRef<BinderBoxInterface>::Adopt(
40 BinderRef::FromJavaBinder(env, box.obj()));
41 if (!proxy) {
42 return unexpected(STATUS_BAD_TYPE);
43 }
44 ASSIGN_OR_RETURN(auto parcel, proxy.PrepareTransaction());
45 ASSIGN_OR_RETURN(const auto reply,
46 proxy.Transact(kUnpack, std::move(parcel)));
47 ASSIGN_OR_RETURN(const size_t num_binders, reply.reader().ReadUint32());
48 std::vector<BinderRef> binders(num_binders);
49 for (size_t i = 0; i < num_binders; ++i) {
50 ASSIGN_OR_RETURN(binders[i], reply.reader().ReadBinder());
51 }
52 return binders;
53 }
54
55 private:
56 ~BinderBox() override = default;
57
58 // SupportsBinder<BinderBoxInterface>:
OnBinderTransaction(transaction_code_t code,const ParcelReader & in,const ParcelWriter & out)59 BinderStatusOr<void> OnBinderTransaction(transaction_code_t code,
60 const ParcelReader& in,
61 const ParcelWriter& out) override {
62 if (code != kUnpack) {
63 return unexpected(STATUS_UNKNOWN_TRANSACTION);
64 }
65 const uint32_t num_binders = checked_cast<uint32_t>(binders_.size());
66 RETURN_IF_ERROR(out.WriteUint32(num_binders));
67 for (uint32_t i = 0; i < num_binders; ++i) {
68 RETURN_IF_ERROR(out.WriteBinder(binders_[i]));
69 }
70 binders_.clear();
71 return ok();
72 }
73
74 std::vector<BinderRef> binders_;
75 };
76
77 } // namespace
78
PackBinderBox(JNIEnv * env,std::vector<BinderRef> binders)79 ScopedJavaLocalRef<jobject> PackBinderBox(JNIEnv* env,
80 std::vector<BinderRef> binders) {
81 if (binders.empty()) {
82 return nullptr;
83 }
84 return MakeRefCounted<BinderBox>(std::move(binders))->GetJavaBinder(env);
85 }
86
UnpackBinderBox(JNIEnv * env,const JavaRef<jobject> & box)87 BinderStatusOr<std::vector<BinderRef>> UnpackBinderBox(
88 JNIEnv* env,
89 const JavaRef<jobject>& box) {
90 return BinderBox::Unpack(env, box);
91 }
92
93 } // namespace base::android
94