The interviewer asked you what you can think of to deliver the big picture across processes.
Shall we have A look at the performance of A, B and C
Student A thinks he knows everything and his level has reached the ceiling of application development. His monthly salary is now 10K
Interviewer: How do you deliver the big picture across processes?
A: It’s very simple. Save the picture to the SD card, then pass the path to the SD card, and read it in another process.
Interviewer: This requires file operation, which is inefficient. Is there any other way?
PutExtra (String name, Parcelable value) is an intent.putextra (String name, Parcelable value).
Interviewer: What are the disadvantages of this method?
A: Too big A Bitmap throws exceptions, so I prefer passing paths
Interviewer: Why did you make an exception?
A:…
Interviewer: Ok, go back and wait for the announcement
B often plays games, watches TV dramas and stays up late in his spare time. His monthly salary is 15K
Interviewer: What’s wrong with an Intent passing a Bitmap directly?
B: too much Bitmap can throw TransactionTooLargeException anomaly, the reason is: the underlying judgment as long as the Binder Transaction fails, and the Intent of data is larger than 200 k will throw this exception. (See: Android_util_binder. CPP file signalExceptionForError method)
Interviewer: Why does the Intent have a size limit?
B: When the Binder mechanism is enabled, the application processes map a 1mb buffer of memory that is shared by all Binder transactions in progress. When using Intent on IPC application cache more than 1 m – the memory of other business, can apply for failure TransactionTooLargeException process. (Well, it won’t be as difficult as last time. See: “What do you know about Binder?” )
Interviewer: How do you get around this limitation?
B: AIDL IPC with Binder is not subject to this restriction. The code is as follows:
Bundle bundle = new Bundle();
bundle.putBinder("binder", new IRemoteGetBitmap.Stub() {
@Override
public Bitmap getBitMap() throws RemoteException {
returnmBitmap; }}); intent.putExtras(bundle);Copy the code
Interviewer: How does that work?
B: I haven’t checked it out yet
Interviewer: Ok, go back and wait for the announcement
Student C insists on learning every day and constantly improves himself. His current monthly salary is 30K
Interviewer: why was by putBinder Bitmap won’t throw TransactionTooLargeException exception
C: How does a Bitmap go to a Parcel in IPC?
Android - 28 Bitmap.cpp static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, ...) {// Take Native Bitmap auto bitmapWrapper = reinterpret_cast< bitmapWrapper *>(bitmapHandle); BitmapWrapper ->getSkBitmap(& Bitmap); int fd = bitmapWrapper->bitmap().getAshmemFd();if(fd >= 0 && ! IsMutable &&p ->allowFds()) {// Bitmap with ashmemFd &&bitmap cannot be modified &&parcel is allowed to write fd to Parcel directly. status = p->writeDupImmutableBlobFileDescriptor(fd);returnJNI_TRUE; } / / does not meet the above conditions will be the Bitmap copied to a new buffer android: : Parcel: : WritableBlob blob. Blob status = p->writeBlob(size, mutableCopy, &blob); Const void* pSrc = bitmap.getPixels(); const void* pSrc = bitmap.getPixels();if (pSrc == NULL) {
memset(blob.data(), 0, size);
} else{ memcpy(blob.data(), pSrc, size); }}Copy the code
Let’s take a look at how writeBlob gets the buffer (note that although the method name is write, the actual writing of data to the buffer is done after the writeBlob method executes).
Android - 28 Parcel.cpp // Maximum size of a blob to transfer in-place. static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) {
if(! MAllowFds | | len < = BLOB_INPLACE_LIMIT) {/ / if not allowed to bring fd, Or the data is less than 16K // Just allocate space in the Parcel buffer to hold the data status = writeInt32(BLOB_INPLACE); void* ptr = writeInplace(len); outBlob->init(-1, ptr, len,false);
returnNO_ERROR; Int fd = ashmem_create_region(int fd = ashmem_create_region);"Parcel Blob", len); void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); . Status = writeFileDescriptor(fd, writeFileDescriptor)true /*takeOwnership*/);
outBlob->init(fd, ptr, len, mutableCopy);
return status; }Copy the code
From the above analysis, we can see that the buffer size of the same Bitmap written to a Parcel is related to Pacel allowFds.
Directly through Intent and Bitmap easy TransactionTooLargeException abnormal, because the Parcel allowFds = false, the Bitmap into the buffer directly to occupy a larger memory.
Next, let’s see when allowFds is set to false:
// Start the Activity and execute the method public ActivityResult to instruments. JavaexecStartActivity(... , Intent intent, ...) {... intent.prepareToLeaveProcess(who); ActivityManager.getService().startActivity(... ,intent,...) } // Intent.java public void preparetoleProcess (Boolean leavingPackage) {// This layer is passed to allowFds, which finally sets the ParcelsetAllowFds(false); . }Copy the code
Interviewer: Too many, you know.
C: To sum up: When the Intent starts, the filesystem descriptor FD is disabled. Bitmaps cannot use shared memory and can only be copied to buffers mapped by Binder. As a result, the buffer limit exceeds and exceptions are triggered. PutBinder prevents descriptors from being disabled by intEnts. Bitmap allowFds defaults to True when writing parcels and uses shared memory to efficiently transfer images.
Interviewer: Yes, let’s talk about something else.
What do you think of the interview performance of these three students?