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