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