• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 
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 
86 private:
87     friend class IMemory;
88     friend class HeapCache;
89 
90     // for debugging in this module
find_heap(const sp<IBinder> & binder)91     static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
92         return gHeapCache->find_heap(binder);
93     }
free_heap(const sp<IBinder> & binder)94     static inline void free_heap(const sp<IBinder>& binder) {
95         gHeapCache->free_heap(binder);
96     }
get_heap(const sp<IBinder> & binder)97     static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
98         return gHeapCache->get_heap(binder);
99     }
dump_heaps()100     static inline void dump_heaps() {
101         gHeapCache->dump_heaps();
102     }
pin_heap() const103     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 
121 enum {
122     GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
123 };
124 
125 class BpMemory : public BpInterface<IMemory>
126 {
127 public:
128     BpMemory(const sp<IBinder>& impl);
129     virtual ~BpMemory();
130     virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
131 
132 private:
133     mutable sp<IMemoryHeap> mHeap;
134     mutable ssize_t mOffset;
135     mutable size_t mSize;
136 };
137 
138 /******************************************************************************/
139 
fastPointer(const sp<IBinder> & binder,ssize_t offset) const140 void* 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 
pointer() const149 void* 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 
size() const158 size_t IMemory::size() const {
159     size_t size;
160     getMemory(NULL, &size);
161     return size;
162 }
163 
offset() const164 ssize_t IMemory::offset() const {
165     ssize_t offset;
166     getMemory(&offset);
167     return offset;
168 }
169 
170 /******************************************************************************/
171 
BpMemory(const sp<IBinder> & impl)172 BpMemory::BpMemory(const sp<IBinder>& impl)
173     : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
174 {
175 }
176 
~BpMemory()177 BpMemory::~BpMemory()
178 {
179 }
180 
getMemory(ssize_t * offset,size_t * size) const181 sp<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 
206 IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
207 
BnMemory()208 BnMemory::BnMemory() {
209 }
210 
~BnMemory()211 BnMemory::~BnMemory() {
212 }
213 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)214 status_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 
BpMemoryHeap(const sp<IBinder> & impl)235 BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
236     : BpInterface<IMemoryHeap>(impl),
237         mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
238 {
239 }
240 
~BpMemoryHeap()241 BpMemoryHeap::~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 
assertMapped() const267 void 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 
assertReallyMapped() const287 void 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=%ld, 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=%ld, 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=%ld, 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 
getHeapID() const336 int BpMemoryHeap::getHeapID() const {
337     assertMapped();
338     return mHeapId;
339 }
340 
getBase() const341 void* BpMemoryHeap::getBase() const {
342     assertMapped();
343     return mBase;
344 }
345 
getSize() const346 size_t BpMemoryHeap::getSize() const {
347     assertMapped();
348     return mSize;
349 }
350 
getFlags() const351 uint32_t BpMemoryHeap::getFlags() const {
352     assertMapped();
353     return mFlags;
354 }
355 
356 // ---------------------------------------------------------------------------
357 
358 IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
359 
BnMemoryHeap()360 BnMemoryHeap::BnMemoryHeap() {
361 }
362 
~BnMemoryHeap()363 BnMemoryHeap::~BnMemoryHeap() {
364 }
365 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)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             return NO_ERROR;
376         } break;
377         default:
378             return BBinder::onTransact(code, data, reply, flags);
379     }
380 }
381 
382 /*****************************************************************************/
383 
HeapCache()384 HeapCache::HeapCache()
385     : DeathRecipient()
386 {
387 }
388 
~HeapCache()389 HeapCache::~HeapCache()
390 {
391 }
392 
binderDied(const wp<IBinder> & binder)393 void HeapCache::binderDied(const wp<IBinder>& binder)
394 {
395     //LOGD("binderDied binder=%p", binder.unsafe_get());
396     free_heap(binder);
397 }
398 
find_heap(const sp<IBinder> & binder)399 sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
400 {
401     Mutex::Autolock _l(mHeapCacheLock);
402     ssize_t i = mHeapCache.indexOfKey(binder);
403     if (i>=0) {
404         heap_info_t& info = mHeapCache.editValueAt(i);
405         LOGD_IF(VERBOSE,
406                 "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
407                 binder.get(), info.heap.get(),
408                 static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
409                 static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
410                 info.count);
411         android_atomic_inc(&info.count);
412         return info.heap;
413     } else {
414         heap_info_t info;
415         info.heap = interface_cast<IMemoryHeap>(binder);
416         info.count = 1;
417         //LOGD("adding binder=%p, heap=%p, count=%d",
418         //      binder.get(), info.heap.get(), info.count);
419         mHeapCache.add(binder, info);
420         return info.heap;
421     }
422 }
423 
pin_heap(const sp<IBinder> & binder)424 void HeapCache::pin_heap(const sp<IBinder>& binder)
425 {
426     Mutex::Autolock _l(mHeapCacheLock);
427     ssize_t i = mHeapCache.indexOfKey(binder);
428     if (i>=0) {
429         heap_info_t& info(mHeapCache.editValueAt(i));
430         android_atomic_inc(&info.count);
431         binder->linkToDeath(this);
432     } else {
433         LOGE("pin_heap binder=%p not found!!!", binder.get());
434     }
435 }
436 
free_heap(const sp<IBinder> & binder)437 void HeapCache::free_heap(const sp<IBinder>& binder)  {
438     free_heap( wp<IBinder>(binder) );
439 }
440 
free_heap(const wp<IBinder> & binder)441 void HeapCache::free_heap(const wp<IBinder>& binder)
442 {
443     sp<IMemoryHeap> rel;
444     {
445         Mutex::Autolock _l(mHeapCacheLock);
446         ssize_t i = mHeapCache.indexOfKey(binder);
447         if (i>=0) {
448             heap_info_t& info(mHeapCache.editValueAt(i));
449             int32_t c = android_atomic_dec(&info.count);
450             if (c == 1) {
451                 LOGD_IF(VERBOSE,
452                         "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
453                         binder.unsafe_get(), info.heap.get(),
454                         static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
455                         static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
456                         info.count);
457                 rel = mHeapCache.valueAt(i).heap;
458                 mHeapCache.removeItemsAt(i);
459             }
460         } else {
461             LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
462         }
463     }
464 }
465 
get_heap(const sp<IBinder> & binder)466 sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
467 {
468     sp<IMemoryHeap> realHeap;
469     Mutex::Autolock _l(mHeapCacheLock);
470     ssize_t i = mHeapCache.indexOfKey(binder);
471     if (i>=0)   realHeap = mHeapCache.valueAt(i).heap;
472     else        realHeap = interface_cast<IMemoryHeap>(binder);
473     return realHeap;
474 }
475 
dump_heaps()476 void HeapCache::dump_heaps()
477 {
478     Mutex::Autolock _l(mHeapCacheLock);
479     int c = mHeapCache.size();
480     for (int i=0 ; i<c ; i++) {
481         const heap_info_t& info = mHeapCache.valueAt(i);
482         BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
483         LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
484                 mHeapCache.keyAt(i).unsafe_get(),
485                 info.heap.get(), info.count,
486                 h->mHeapId, h->mBase, h->mSize);
487     }
488 }
489 
490 
491 // ---------------------------------------------------------------------------
492 }; // namespace android
493