Skip to content

Commit 56c58f6

Browse files
author
Jeff Brown
committed
Transfer large bitmaps using ashmem.
Bug: 5224703 Change-Id: Ic7481dd9f173986f085a8bbdcc59bbe9830d7a44
1 parent 4c25311 commit 56c58f6

File tree

4 files changed

+167
-10
lines changed

4 files changed

+167
-10
lines changed

core/jni/android/graphics/Bitmap.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,20 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
392392
SkSafeUnref(ctable);
393393

394394
size_t size = bitmap->getSize();
395+
396+
android::Parcel::ReadableBlob blob;
397+
android::status_t status = p->readBlob(size, &blob);
398+
if (status) {
399+
doThrowRE(env, "Could not read bitmap from parcel blob.");
400+
delete bitmap;
401+
return NULL;
402+
}
403+
395404
bitmap->lockPixels();
396-
memcpy(bitmap->getPixels(), p->readInplace(size), size);
405+
memcpy(bitmap->getPixels(), blob.data(), size);
397406
bitmap->unlockPixels();
398407

408+
blob.release();
399409
return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, density);
400410
}
401411

@@ -431,17 +441,24 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
431441
}
432442

433443
size_t size = bitmap->getSize();
434-
bitmap->lockPixels();
435-
void* pDst = p->writeInplace(size);
436444

437-
const void* pSrc = bitmap->getPixels();
445+
android::Parcel::WritableBlob blob;
446+
android::status_t status = p->writeBlob(size, &blob);
447+
if (status) {
448+
doThrowRE(env, "Could not write bitmap to parcel blob.");
449+
return false;
450+
}
438451

452+
bitmap->lockPixels();
453+
const void* pSrc = bitmap->getPixels();
439454
if (pSrc == NULL) {
440-
memset(pDst, 0, size);
455+
memset(blob.data(), 0, size);
441456
} else {
442-
memcpy(pDst, pSrc, size);
457+
memcpy(blob.data(), pSrc, size);
443458
}
444459
bitmap->unlockPixels();
460+
461+
blob.release();
445462
return true;
446463
}
447464

graphics/java/android/graphics/Bitmap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ public Bitmap[] newArray(int size) {
10611061
* No special parcel contents.
10621062
*/
10631063
public int describeContents() {
1064-
return 0;
1064+
return Parcelable.CONTENTS_FILE_DESCRIPTOR; // uses parcel blobs
10651065
}
10661066

10671067
/**

include/binder/Parcel.h

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ struct flat_binder_object; // defined in support_p/binder_module.h
3838
class Parcel
3939
{
4040
public:
41+
class ReadableBlob;
42+
class WritableBlob;
43+
4144
Parcel();
4245
~Parcel();
4346

@@ -109,7 +112,13 @@ class Parcel
109112
// Place a file descriptor into the parcel. A dup of the fd is made, which
110113
// will be closed once the parcel is destroyed.
111114
status_t writeDupFileDescriptor(int fd);
112-
115+
116+
// Writes a blob to the parcel.
117+
// If the blob is small, then it is stored in-place, otherwise it is
118+
// transferred by way of an anonymous shared memory region.
119+
// The caller should call release() on the blob after writing its contents.
120+
status_t writeBlob(size_t len, WritableBlob* outBlob);
121+
113122
status_t writeObject(const flat_binder_object& val, bool nullMetaData);
114123

115124
// Like Parcel.java's writeNoException(). Just writes a zero int32.
@@ -157,7 +166,11 @@ class Parcel
157166
// Retrieve a file descriptor from the parcel. This returns the raw fd
158167
// in the parcel, which you do not own -- use dup() to get your own copy.
159168
int readFileDescriptor() const;
160-
169+
170+
// Reads a blob from the parcel.
171+
// The caller should call release() on the blob after reading its contents.
172+
status_t readBlob(size_t len, ReadableBlob* outBlob) const;
173+
161174
const flat_binder_object* readObject(bool nullMetaData) const;
162175

163176
// Explicitly close all file descriptors in the parcel.
@@ -177,7 +190,7 @@ class Parcel
177190
release_func relFunc, void* relCookie);
178191

179192
void print(TextOutput& to, uint32_t flags = 0) const;
180-
193+
181194
private:
182195
Parcel(const Parcel& o);
183196
Parcel& operator=(const Parcel& o);
@@ -215,6 +228,36 @@ class Parcel
215228

216229
release_func mOwner;
217230
void* mOwnerCookie;
231+
232+
class Blob {
233+
public:
234+
Blob();
235+
~Blob();
236+
237+
void release();
238+
inline size_t size() const { return mSize; }
239+
240+
protected:
241+
void init(bool mapped, void* data, size_t size);
242+
void clear();
243+
244+
bool mMapped;
245+
void* mData;
246+
size_t mSize;
247+
};
248+
249+
public:
250+
class ReadableBlob : public Blob {
251+
friend class Parcel;
252+
public:
253+
inline const void* data() const { return mData; }
254+
};
255+
256+
class WritableBlob : public Blob {
257+
friend class Parcel;
258+
public:
259+
inline void* data() { return mData; }
260+
};
218261
};
219262

220263
// ---------------------------------------------------------------------------

libs/binder/Parcel.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@
3030
#include <utils/TextOutput.h>
3131
#include <utils/misc.h>
3232
#include <utils/Flattenable.h>
33+
#include <cutils/ashmem.h>
3334

3435
#include <private/binder/binder_module.h>
3536

3637
#include <stdio.h>
3738
#include <stdlib.h>
3839
#include <stdint.h>
40+
#include <sys/mman.h>
3941

4042
#ifndef INT32_MAX
4143
#define INT32_MAX ((int32_t)(2147483647))
@@ -54,6 +56,9 @@
5456
// Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
5557
#define EX_HAS_REPLY_HEADER -128
5658

59+
// Maximum size of a blob to transfer in-place.
60+
static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024;
61+
5762
// XXX This can be made public if we want to provide
5863
// support for typed data.
5964
struct small_flat_data
@@ -706,6 +711,47 @@ status_t Parcel::writeDupFileDescriptor(int fd)
706711
return writeObject(obj, true);
707712
}
708713

714+
status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
715+
{
716+
if (len <= IN_PLACE_BLOB_LIMIT) {
717+
LOGV("writeBlob: write in place");
718+
void* ptr = writeInplace(len);
719+
if (!ptr) return NO_MEMORY;
720+
721+
outBlob->init(false /*mapped*/, ptr, len);
722+
return NO_ERROR;
723+
}
724+
725+
LOGV("writeBlob: write to ashmem");
726+
int fd = ashmem_create_region("Parcel Blob", len);
727+
if (fd < 0) return NO_MEMORY;
728+
729+
status_t status;
730+
int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
731+
if (result < 0) {
732+
status = -result;
733+
} else {
734+
void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
735+
if (ptr == MAP_FAILED) {
736+
status = -errno;
737+
} else {
738+
result = ashmem_set_prot_region(fd, PROT_READ);
739+
if (result < 0) {
740+
status = -result;
741+
} else {
742+
status = writeFileDescriptor(fd);
743+
if (!status) {
744+
outBlob->init(true /*mapped*/, ptr, len);
745+
return NO_ERROR;
746+
}
747+
}
748+
}
749+
::munmap(ptr, len);
750+
}
751+
::close(fd);
752+
return status;
753+
}
754+
709755
status_t Parcel::write(const Flattenable& val)
710756
{
711757
status_t err;
@@ -1025,6 +1071,28 @@ int Parcel::readFileDescriptor() const
10251071
return BAD_TYPE;
10261072
}
10271073

1074+
status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
1075+
{
1076+
if (len <= IN_PLACE_BLOB_LIMIT) {
1077+
LOGV("readBlob: read in place");
1078+
const void* ptr = readInplace(len);
1079+
if (!ptr) return BAD_VALUE;
1080+
1081+
outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len);
1082+
return NO_ERROR;
1083+
}
1084+
1085+
LOGV("readBlob: read from ashmem");
1086+
int fd = readFileDescriptor();
1087+
if (fd == int(BAD_TYPE)) return BAD_VALUE;
1088+
1089+
void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
1090+
if (!ptr) return NO_MEMORY;
1091+
1092+
outBlob->init(true /*mapped*/, ptr, len);
1093+
return NO_ERROR;
1094+
}
1095+
10281096
status_t Parcel::read(Flattenable& val) const
10291097
{
10301098
// size
@@ -1452,4 +1520,33 @@ void Parcel::scanForFds() const
14521520
mFdsKnown = true;
14531521
}
14541522

1523+
// --- Parcel::Blob ---
1524+
1525+
Parcel::Blob::Blob() :
1526+
mMapped(false), mData(NULL), mSize(0) {
1527+
}
1528+
1529+
Parcel::Blob::~Blob() {
1530+
release();
1531+
}
1532+
1533+
void Parcel::Blob::release() {
1534+
if (mMapped && mData) {
1535+
::munmap(mData, mSize);
1536+
}
1537+
clear();
1538+
}
1539+
1540+
void Parcel::Blob::init(bool mapped, void* data, size_t size) {
1541+
mMapped = mapped;
1542+
mData = data;
1543+
mSize = size;
1544+
}
1545+
1546+
void Parcel::Blob::clear() {
1547+
mMapped = false;
1548+
mData = NULL;
1549+
mSize = 0;
1550+
}
1551+
14551552
}; // namespace android

0 commit comments

Comments
 (0)