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