Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <android/binder_ibinder.h> |
| 18 | #include "AIBinder_internal.h" |
| 19 | |
| 20 | #include <android/binder_status.h> |
| 21 | #include "AParcel_internal.h" |
| 22 | |
| 23 | #include <android-base/logging.h> |
| 24 | |
| 25 | using ::android::IBinder; |
| 26 | using ::android::Parcel; |
| 27 | using ::android::sp; |
| 28 | using ::android::String16; |
| 29 | using ::android::wp; |
| 30 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 31 | namespace ABBinderTag { |
| 32 | |
| 33 | static const void* kId = "ABBinder"; |
| 34 | static void* kValue = static_cast<void*>(new bool{true}); |
| 35 | void cleanId(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */}; |
| 36 | |
| 37 | static void attach(const sp<IBinder>& binder) { |
| 38 | binder->attachObject(kId, kValue, nullptr /*cookie*/, cleanId); |
| 39 | } |
| 40 | static bool has(const sp<IBinder>& binder) { |
| 41 | return binder != nullptr && binder->findObject(kId) == kValue; |
| 42 | } |
| 43 | |
| 44 | } // namespace ABBinderTag |
| 45 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 46 | AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {} |
| 47 | AIBinder::~AIBinder() {} |
| 48 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 49 | bool AIBinder::associateClass(const AIBinder_Class* clazz) { |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 50 | using ::android::String8; |
| 51 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 52 | if (clazz == nullptr) return false; |
| 53 | if (mClazz == clazz) return true; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 54 | |
| 55 | String8 newDescriptor(clazz->getInterfaceDescriptor()); |
| 56 | |
| 57 | if (mClazz != nullptr) { |
| 58 | String8 currentDescriptor(mClazz->getInterfaceDescriptor()); |
| 59 | if (newDescriptor == currentDescriptor) { |
| 60 | LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor |
| 61 | << "' match during associateClass, but they are different class objects. " |
| 62 | "Class descriptor collision?"; |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 63 | } else { |
| 64 | LOG(ERROR) << __func__ |
| 65 | << ": Class cannot be associated on object which already has a class. " |
| 66 | "Trying to associate to '" |
| 67 | << newDescriptor.c_str() << "' but already set to '" |
| 68 | << currentDescriptor.c_str() << "'."; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 69 | } |
| 70 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 71 | // always a failure because we know mClazz != clazz |
| 72 | return false; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 73 | } |
| 74 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 75 | CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor |
| 76 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 77 | String8 descriptor(getBinder()->getInterfaceDescriptor()); |
| 78 | if (descriptor != newDescriptor) { |
| 79 | LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str() |
| 80 | << "' but descriptor is actually '" << descriptor.c_str() << "'."; |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 81 | return false; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 82 | } |
| 83 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 84 | // if this is a local object, it's not one known to libbinder_ndk |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 85 | mClazz = clazz; |
| 86 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 87 | return true; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData) |
| 91 | : AIBinder(clazz), BBinder(), mUserData(userData) { |
| 92 | CHECK(clazz != nullptr); |
| 93 | } |
| 94 | ABBinder::~ABBinder() { |
| 95 | getClass()->onDestroy(mUserData); |
| 96 | } |
| 97 | |
| 98 | const String16& ABBinder::getInterfaceDescriptor() const { |
| 99 | return getClass()->getInterfaceDescriptor(); |
| 100 | } |
| 101 | |
| 102 | binder_status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply, |
| 103 | binder_flags_t flags) { |
| 104 | if (isUserCommand(code)) { |
| 105 | if (!data.checkInterface(this)) { |
| 106 | return EX_ILLEGAL_STATE; |
| 107 | } |
| 108 | |
| 109 | const AParcel in = AParcel::readOnly(this, &data); |
| 110 | AParcel out = AParcel(this, reply, false /*owns*/); |
| 111 | |
| 112 | return getClass()->onTransact(this, code, &in, &out); |
| 113 | } else { |
| 114 | return BBinder::onTransact(code, data, reply, flags); |
| 115 | } |
| 116 | } |
| 117 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 118 | ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder) |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 119 | : AIBinder(nullptr /*clazz*/), BpRefBase(binder) { |
| 120 | CHECK(binder != nullptr); |
| 121 | } |
| 122 | ABpBinder::~ABpBinder() {} |
| 123 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 124 | sp<AIBinder> ABpBinder::fromBinder(const ::android::sp<::android::IBinder>& binder) { |
| 125 | if (binder == nullptr) { |
| 126 | return nullptr; |
| 127 | } |
| 128 | if (ABBinderTag::has(binder)) { |
| 129 | return static_cast<ABBinder*>(binder.get()); |
| 130 | } |
| 131 | return new ABpBinder(binder); |
| 132 | } |
| 133 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 134 | struct AIBinder_Weak { |
| 135 | wp<AIBinder> binder; |
| 136 | }; |
| 137 | AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) { |
Steven Moreland | 5ccb70f | 2018-09-04 16:30:21 -0700 | [diff] [blame] | 138 | if (binder == nullptr) { |
| 139 | return nullptr; |
| 140 | } |
| 141 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 142 | return new AIBinder_Weak{wp<AIBinder>(binder)}; |
| 143 | } |
Steven Moreland | 5ccb70f | 2018-09-04 16:30:21 -0700 | [diff] [blame] | 144 | void AIBinder_Weak_delete(AIBinder_Weak** weakBinder) { |
| 145 | if (weakBinder == nullptr) { |
| 146 | return; |
| 147 | } |
| 148 | |
| 149 | delete *weakBinder; |
| 150 | *weakBinder = nullptr; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 151 | } |
| 152 | AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) { |
Steven Moreland | 5ccb70f | 2018-09-04 16:30:21 -0700 | [diff] [blame] | 153 | if (weakBinder == nullptr) { |
| 154 | return nullptr; |
| 155 | } |
| 156 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 157 | sp<AIBinder> binder = weakBinder->binder.promote(); |
| 158 | AIBinder_incStrong(binder.get()); |
| 159 | return binder.get(); |
| 160 | } |
| 161 | |
| 162 | AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, |
| 163 | AIBinder_Class_onDestroy onDestroy, |
| 164 | AIBinder_Class_onTransact onTransact) |
| 165 | : onCreate(onCreate), |
| 166 | onDestroy(onDestroy), |
| 167 | onTransact(onTransact), |
| 168 | mInterfaceDescriptor(interfaceDescriptor) {} |
| 169 | |
| 170 | AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor, |
| 171 | AIBinder_Class_onCreate onCreate, |
| 172 | AIBinder_Class_onDestroy onDestroy, |
| 173 | AIBinder_Class_onTransact onTransact) { |
| 174 | if (interfaceDescriptor == nullptr || onCreate == nullptr || onDestroy == nullptr || |
| 175 | onTransact == nullptr) { |
| 176 | return nullptr; |
| 177 | } |
| 178 | |
| 179 | return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact); |
| 180 | } |
| 181 | |
| 182 | AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) { |
| 183 | if (clazz == nullptr) { |
| 184 | LOG(ERROR) << __func__ << ": Must provide class to construct local binder."; |
| 185 | return nullptr; |
| 186 | } |
| 187 | |
| 188 | void* userData = clazz->onCreate(args); |
| 189 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 190 | sp<AIBinder> ret = new ABBinder(clazz, userData); |
| 191 | ABBinderTag::attach(ret->getBinder()); |
| 192 | |
| 193 | AIBinder_incStrong(ret.get()); |
| 194 | return ret.get(); |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 195 | } |
| 196 | |
Steven Moreland | 5ea54da | 2018-09-04 13:29:55 -0700 | [diff] [blame] | 197 | bool AIBinder_isRemote(const AIBinder* binder) { |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 198 | if (binder == nullptr) { |
| 199 | return true; |
| 200 | } |
| 201 | |
| 202 | return binder->isRemote(); |
| 203 | } |
| 204 | |
| 205 | void AIBinder_incStrong(AIBinder* binder) { |
| 206 | if (binder == nullptr) { |
| 207 | LOG(ERROR) << __func__ << ": on null binder"; |
| 208 | return; |
| 209 | } |
| 210 | |
| 211 | binder->incStrong(nullptr); |
| 212 | } |
| 213 | void AIBinder_decStrong(AIBinder* binder) { |
| 214 | if (binder == nullptr) { |
| 215 | LOG(ERROR) << __func__ << ": on null binder"; |
| 216 | return; |
| 217 | } |
| 218 | |
| 219 | binder->decStrong(nullptr); |
| 220 | } |
| 221 | int32_t AIBinder_debugGetRefCount(AIBinder* binder) { |
| 222 | if (binder == nullptr) { |
| 223 | LOG(ERROR) << __func__ << ": on null binder"; |
| 224 | return -1; |
| 225 | } |
| 226 | |
| 227 | return binder->getStrongCount(); |
| 228 | } |
| 229 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 230 | bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) { |
| 231 | if (binder == nullptr) { |
| 232 | return false; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 233 | } |
| 234 | |
Steven Moreland | 71cddc3 | 2018-08-30 23:39:22 -0700 | [diff] [blame] | 235 | return binder->associateClass(clazz); |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | const AIBinder_Class* AIBinder_getClass(AIBinder* binder) { |
| 239 | if (binder == nullptr) { |
| 240 | return nullptr; |
| 241 | } |
| 242 | |
| 243 | return binder->getClass(); |
| 244 | } |
| 245 | |
| 246 | void* AIBinder_getUserData(AIBinder* binder) { |
| 247 | if (binder == nullptr) { |
| 248 | return nullptr; |
| 249 | } |
| 250 | |
| 251 | ABBinder* bBinder = binder->asABBinder(); |
| 252 | if (bBinder == nullptr) { |
| 253 | return nullptr; |
| 254 | } |
| 255 | |
| 256 | return bBinder->getUserData(); |
| 257 | } |
| 258 | |
| 259 | binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) { |
| 260 | if (binder == nullptr || in == nullptr) { |
| 261 | LOG(ERROR) << __func__ << ": requires non-null parameters."; |
| 262 | return EX_NULL_POINTER; |
| 263 | } |
| 264 | const AIBinder_Class* clazz = binder->getClass(); |
| 265 | if (clazz == nullptr) { |
| 266 | LOG(ERROR) << __func__ |
| 267 | << ": Class must be defined for a remote binder transaction. See " |
| 268 | "AIBinder_associateClass."; |
| 269 | return EX_ILLEGAL_STATE; |
| 270 | } |
| 271 | |
Steven Moreland | 3527c2e | 2018-09-05 17:07:14 -0700 | [diff] [blame^] | 272 | if (!binder->isRemote()) { |
| 273 | LOG(WARNING) << "A binder object at " << binder << " is being transacted on, however, this object is in the same process as its proxy. Transacting with this binder is expensive compared to just calling the corresponding functionality in the same process."; |
| 274 | } |
| 275 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 276 | *in = new AParcel(binder); |
| 277 | binder_status_t status = (**in)->writeInterfaceToken(clazz->getInterfaceDescriptor()); |
| 278 | if (status != EX_NONE) { |
| 279 | delete *in; |
| 280 | *in = nullptr; |
| 281 | } |
| 282 | |
| 283 | return status; |
| 284 | } |
| 285 | |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 286 | binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in, |
| 287 | AParcel** out, binder_flags_t flags) { |
| 288 | if (in == nullptr) { |
| 289 | LOG(ERROR) << __func__ << ": requires non-null in parameter"; |
| 290 | return EX_NULL_POINTER; |
| 291 | } |
| 292 | |
Steven Moreland | caa776c | 2018-09-04 13:48:11 -0700 | [diff] [blame] | 293 | using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>; |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 294 | // This object is the input to the transaction. This function takes ownership of it and deletes |
| 295 | // it. |
Steven Moreland | caa776c | 2018-09-04 13:48:11 -0700 | [diff] [blame] | 296 | AutoParcelDestroyer forIn(in, AParcel_delete); |
Steven Moreland | 2e87adc | 2018-08-20 19:47:00 -0700 | [diff] [blame] | 297 | |
| 298 | if (!isUserCommand(code)) { |
| 299 | LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK."; |
| 300 | return EX_UNSUPPORTED_OPERATION; |
| 301 | } |
| 302 | |
| 303 | if ((flags & ~FLAG_ONEWAY) != 0) { |
| 304 | LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags; |
| 305 | return EX_ILLEGAL_ARGUMENT; |
| 306 | } |
| 307 | |
| 308 | if (binder == nullptr || *in == nullptr || out == nullptr) { |
| 309 | LOG(ERROR) << __func__ << ": requires non-null parameters."; |
| 310 | return EX_NULL_POINTER; |
| 311 | } |
| 312 | |
| 313 | if ((*in)->getBinder() != binder) { |
| 314 | LOG(ERROR) << __func__ << ": parcel is associated with binder object " << binder |
| 315 | << " but called with " << (*in)->getBinder(); |
| 316 | return EX_ILLEGAL_STATE; |
| 317 | } |
| 318 | |
| 319 | *out = new AParcel(binder); |
| 320 | |
| 321 | binder_status_t parcelStatus = |
| 322 | binder->getBinder()->transact(code, *(*in)->operator->(), (*out)->operator->(), flags); |
| 323 | |
| 324 | if (parcelStatus != EX_NONE) { |
| 325 | delete *out; |
| 326 | *out = nullptr; |
| 327 | } |
| 328 | |
| 329 | return parcelStatus; |
| 330 | } |