1 /* 2 * Copyright (C) 2008 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 #define LOG_TAG "IMemory" 18 19 #include <stdint.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <fcntl.h> 23 #include <unistd.h> 24 25 #include <sys/types.h> 26 #include <sys/mman.h> 27 28 #include <binder/IMemory.h> 29 #include <cutils/log.h> 30 #include <utils/KeyedVector.h> 31 #include <utils/threads.h> 32 #include <utils/Atomic.h> 33 #include <binder/Parcel.h> 34 #include <utils/CallStack.h> 35 36 #define VERBOSE 0 37 38 namespace android { 39 // --------------------------------------------------------------------------- 40 41 class HeapCache : public IBinder::DeathRecipient 42 { 43 public: 44 HeapCache(); 45 virtual ~HeapCache(); 46 47 virtual void binderDied(const wp<IBinder>& who); 48 49 sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); 50 void free_heap(const sp<IBinder>& binder); 51 sp<IMemoryHeap> get_heap(const sp<IBinder>& binder); 52 void dump_heaps(); 53 54 private: 55 // For IMemory.cpp 56 struct heap_info_t { 57 sp<IMemoryHeap> heap; 58 int32_t count; 59 }; 60 61 void free_heap(const wp<IBinder>& binder); 62 63 Mutex mHeapCacheLock; 64 KeyedVector< wp<IBinder>, heap_info_t > mHeapCache; 65 }; 66 67 static sp<HeapCache> gHeapCache = new HeapCache(); 68 69 /******************************************************************************/ 70 71 enum { 72 HEAP_ID = IBinder::FIRST_CALL_TRANSACTION 73 }; 74 75 class BpMemoryHeap : public BpInterface<IMemoryHeap> 76 { 77 public: 78 BpMemoryHeap(const sp<IBinder>& impl); 79 virtual ~BpMemoryHeap(); 80 81 virtual int getHeapID() const; 82 virtual void* getBase() const; 83 virtual size_t getSize() const; 84 virtual uint32_t getFlags() const; 85 virtual uint32_t getOffset() const; 86 87 private: 88 friend class IMemory; 89 friend class HeapCache; 90 91 // for debugging in this module 92 static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) { 93 return gHeapCache->find_heap(binder); 94 } 95 static inline void free_heap(const sp<IBinder>& binder) { 96 gHeapCache->free_heap(binder); 97 } 98 static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) { 99 return gHeapCache->get_heap(binder); 100 } 101 static inline void dump_heaps() { 102 gHeapCache->dump_heaps(); 103 } 104 105 void assertMapped() const; 106 void assertReallyMapped() const; 107 108 mutable volatile int32_t mHeapId; 109 mutable void* mBase; 110 mutable size_t mSize; 111 mutable uint32_t mFlags; 112 mutable uint32_t mOffset; 113 mutable bool mRealHeap; 114 mutable Mutex mLock; 115 }; 116 117 // ---------------------------------------------------------------------------- 118 119 enum { 120 GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION 121 }; 122 123 class BpMemory : public BpInterface<IMemory> 124 { 125 public: 126 BpMemory(const sp<IBinder>& impl); 127 virtual ~BpMemory(); 128 virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const; 129 130 private: 131 mutable sp<IMemoryHeap> mHeap; 132 mutable ssize_t mOffset; 133 mutable size_t mSize; 134 }; 135 136 /******************************************************************************/ 137 138 void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const 139 { 140 sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder); 141 void* const base = realHeap->base(); 142 if (base == MAP_FAILED) 143 return 0; 144 return static_cast<char*>(base) + offset; 145 } 146 147 void* IMemory::pointer() const { 148 ssize_t offset; 149 sp<IMemoryHeap> heap = getMemory(&offset); 150 void* const base = heap!=0 ? heap->base() : MAP_FAILED; 151 if (base == MAP_FAILED) 152 return 0; 153 return static_cast<char*>(base) + offset; 154 } 155 156 size_t IMemory::size() const { 157 size_t size; 158 getMemory(NULL, &size); 159 return size; 160 } 161 162 ssize_t IMemory::offset() const { 163 ssize_t offset; 164 getMemory(&offset); 165 return offset; 166 } 167 168 /******************************************************************************/ 169 170 BpMemory::BpMemory(const sp<IBinder>& impl) 171 : BpInterface<IMemory>(impl), mOffset(0), mSize(0) 172 { 173 } 174 175 BpMemory::~BpMemory() 176 { 177 } 178 179 sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const 180 { 181 if (mHeap == 0) { 182 Parcel data, reply; 183 data.writeInterfaceToken(IMemory::getInterfaceDescriptor()); 184 if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) { 185 sp<IBinder> heap = reply.readStrongBinder(); 186 ssize_t o = reply.readInt32(); 187 size_t s = reply.readInt32(); 188 if (heap != 0) { 189 mHeap = interface_cast<IMemoryHeap>(heap); 190 if (mHeap != 0) { 191 size_t heapSize = mHeap->getSize(); 192 if (s <= heapSize 193 && o >= 0 194 && (static_cast<size_t>(o) <= heapSize - s)) { 195 mOffset = o; 196 mSize = s; 197 } else { 198 // Hm. 199 android_errorWriteWithInfoLog(0x534e4554, 200 "26877992", -1, NULL, 0); 201 mOffset = 0; 202 mSize = 0; 203 } 204 } 205 } 206 } 207 } 208 if (offset) *offset = mOffset; 209 if (size) *size = mSize; 210 return (mSize > 0) ? mHeap : 0; 211 } 212 213 // --------------------------------------------------------------------------- 214 215 IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory"); 216 217 BnMemory::BnMemory() { 218 } 219 220 BnMemory::~BnMemory() { 221 } 222 223 status_t BnMemory::onTransact( 224 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 225 { 226 switch(code) { 227 case GET_MEMORY: { 228 CHECK_INTERFACE(IMemory, data, reply); 229 ssize_t offset; 230 size_t size; 231 reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) ); 232 reply->writeInt32(offset); 233 reply->writeInt32(size); 234 return NO_ERROR; 235 } break; 236 default: 237 return BBinder::onTransact(code, data, reply, flags); 238 } 239 } 240 241 242 /******************************************************************************/ 243 244 BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl) 245 : BpInterface<IMemoryHeap>(impl), 246 mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mOffset(0), mRealHeap(false) 247 { 248 } 249 250 BpMemoryHeap::~BpMemoryHeap() { 251 if (mHeapId != -1) { 252 close(mHeapId); 253 if (mRealHeap) { 254 // by construction we're the last one 255 if (mBase != MAP_FAILED) { 256 sp<IBinder> binder = IInterface::asBinder(this); 257 258 if (VERBOSE) { 259 ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d", 260 binder.get(), this, mSize, mHeapId); 261 CallStack stack(LOG_TAG); 262 } 263 264 munmap(mBase, mSize); 265 } 266 } else { 267 // remove from list only if it was mapped before 268 sp<IBinder> binder = IInterface::asBinder(this); 269 free_heap(binder); 270 } 271 } 272 } 273 274 void BpMemoryHeap::assertMapped() const 275 { 276 if (mHeapId == -1) { 277 sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this))); 278 sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get())); 279 heap->assertReallyMapped(); 280 if (heap->mBase != MAP_FAILED) { 281 Mutex::Autolock _l(mLock); 282 if (mHeapId == -1) { 283 mBase = heap->mBase; 284 mSize = heap->mSize; 285 mOffset = heap->mOffset; 286 android_atomic_write( dup( heap->mHeapId ), &mHeapId ); 287 } 288 } else { 289 // something went wrong 290 free_heap(binder); 291 } 292 } 293 } 294 295 void BpMemoryHeap::assertReallyMapped() const 296 { 297 if (mHeapId == -1) { 298 299 // remote call without mLock held, worse case scenario, we end up 300 // calling transact() from multiple threads, but that's not a problem, 301 // only mmap below must be in the critical section. 302 303 Parcel data, reply; 304 data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor()); 305 status_t err = remote()->transact(HEAP_ID, data, &reply); 306 int parcel_fd = reply.readFileDescriptor(); 307 ssize_t size = reply.readInt32(); 308 uint32_t flags = reply.readInt32(); 309 uint32_t offset = reply.readInt32(); 310 311 ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)", 312 IInterface::asBinder(this).get(), 313 parcel_fd, size, err, strerror(-err)); 314 315 Mutex::Autolock _l(mLock); 316 if (mHeapId == -1) { 317 int fd = dup( parcel_fd ); 318 ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)", 319 parcel_fd, size, err, strerror(errno)); 320 321 int access = PROT_READ; 322 if (!(flags & READ_ONLY)) { 323 access |= PROT_WRITE; 324 } 325 326 mRealHeap = true; 327 mBase = mmap(0, size, access, MAP_SHARED, fd, offset); 328 if (mBase == MAP_FAILED) { 329 ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)", 330 IInterface::asBinder(this).get(), size, fd, strerror(errno)); 331 close(fd); 332 } else { 333 mSize = size; 334 mFlags = flags; 335 mOffset = offset; 336 android_atomic_write(fd, &mHeapId); 337 } 338 } 339 } 340 } 341 342 int BpMemoryHeap::getHeapID() const { 343 assertMapped(); 344 return mHeapId; 345 } 346 347 void* BpMemoryHeap::getBase() const { 348 assertMapped(); 349 return mBase; 350 } 351 352 size_t BpMemoryHeap::getSize() const { 353 assertMapped(); 354 return mSize; 355 } 356 357 uint32_t BpMemoryHeap::getFlags() const { 358 assertMapped(); 359 return mFlags; 360 } 361 362 uint32_t BpMemoryHeap::getOffset() const { 363 assertMapped(); 364 return mOffset; 365 } 366 367 // --------------------------------------------------------------------------- 368 369 IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap"); 370 371 BnMemoryHeap::BnMemoryHeap() { 372 } 373 374 BnMemoryHeap::~BnMemoryHeap() { 375 } 376 377 status_t BnMemoryHeap::onTransact( 378 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 379 { 380 switch(code) { 381 case HEAP_ID: { 382 CHECK_INTERFACE(IMemoryHeap, data, reply); 383 reply->writeFileDescriptor(getHeapID()); 384 reply->writeInt32(getSize()); 385 reply->writeInt32(getFlags()); 386 reply->writeInt32(getOffset()); 387 return NO_ERROR; 388 } break; 389 default: 390 return BBinder::onTransact(code, data, reply, flags); 391 } 392 } 393 394 /*****************************************************************************/ 395 396 HeapCache::HeapCache() 397 : DeathRecipient() 398 { 399 } 400 401 HeapCache::~HeapCache() 402 { 403 } 404 405 void HeapCache::binderDied(const wp<IBinder>& binder) 406 { 407 //ALOGD("binderDied binder=%p", binder.unsafe_get()); 408 free_heap(binder); 409 } 410 411 sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) 412 { 413 Mutex::Autolock _l(mHeapCacheLock); 414 ssize_t i = mHeapCache.indexOfKey(binder); 415 if (i>=0) { 416 heap_info_t& info = mHeapCache.editValueAt(i); 417 ALOGD_IF(VERBOSE, 418 "found binder=%p, heap=%p, size=%zu, fd=%d, count=%d", 419 binder.get(), info.heap.get(), 420 static_cast<BpMemoryHeap*>(info.heap.get())->mSize, 421 static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, 422 info.count); 423 android_atomic_inc(&info.count); 424 return info.heap; 425 } else { 426 heap_info_t info; 427 info.heap = interface_cast<IMemoryHeap>(binder); 428 info.count = 1; 429 //ALOGD("adding binder=%p, heap=%p, count=%d", 430 // binder.get(), info.heap.get(), info.count); 431 mHeapCache.add(binder, info); 432 return info.heap; 433 } 434 } 435 436 void HeapCache::free_heap(const sp<IBinder>& binder) { 437 free_heap( wp<IBinder>(binder) ); 438 } 439 440 void HeapCache::free_heap(const wp<IBinder>& binder) 441 { 442 sp<IMemoryHeap> rel; 443 { 444 Mutex::Autolock _l(mHeapCacheLock); 445 ssize_t i = mHeapCache.indexOfKey(binder); 446 if (i>=0) { 447 heap_info_t& info(mHeapCache.editValueAt(i)); 448 int32_t c = android_atomic_dec(&info.count); 449 if (c == 1) { 450 ALOGD_IF(VERBOSE, 451 "removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d", 452 binder.unsafe_get(), info.heap.get(), 453 static_cast<BpMemoryHeap*>(info.heap.get())->mSize, 454 static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, 455 info.count); 456 rel = mHeapCache.valueAt(i).heap; 457 mHeapCache.removeItemsAt(i); 458 } 459 } else { 460 ALOGE("free_heap binder=%p not found!!!", binder.unsafe_get()); 461 } 462 } 463 } 464 465 sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder) 466 { 467 sp<IMemoryHeap> realHeap; 468 Mutex::Autolock _l(mHeapCacheLock); 469 ssize_t i = mHeapCache.indexOfKey(binder); 470 if (i>=0) realHeap = mHeapCache.valueAt(i).heap; 471 else realHeap = interface_cast<IMemoryHeap>(binder); 472 return realHeap; 473 } 474 475 void HeapCache::dump_heaps() 476 { 477 Mutex::Autolock _l(mHeapCacheLock); 478 int c = mHeapCache.size(); 479 for (int i=0 ; i<c ; i++) { 480 const heap_info_t& info = mHeapCache.valueAt(i); 481 BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get())); 482 ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)", 483 mHeapCache.keyAt(i).unsafe_get(), 484 info.heap.get(), info.count, 485 h->mHeapId, h->mBase, h->mSize); 486 } 487 } 488 489 490 // --------------------------------------------------------------------------- 491 }; // namespace android 492