Log:
09-13 11:46:42.093 14778 17309 I dalvikvm: Ljava/lang/RuntimeException;: No memory in memObj09-13 11:46:42.093 14778 17309 I dalvikvm: at android.database.CursorWindow.native_init(Native Method)09-13 11:46:42.093 14778 17309 I dalvikvm: at android.database.CursorWindow.<init>(CursorWindow.java:569)09-13 11:46:42.093 14778 17309 I dalvikvm: at android.database.CursorWindow.<init>(CursorWindow.java:36)09-13 11:46:42.093 14778 17309 I dalvikvm: at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:544)09-13 11:46:42.093 14778 17309 I dalvikvm: at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:542)09-13 11:46:42.093 14778 17309 I dalvikvm: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:116)09-13 11:46:42.093 14778 17309 I dalvikvm: at android.os.Binder.execTransact(Binder.java:336)09-13 11:46:42.093 14778 17309 I dalvikvm: at dalvik.system.NativeStart.run(Native Method)09-13 11:46:42.093 14778 17309 I dalvikvm: "Binder Thread #3" prio=5 tid=10 NATIVE09-13 11:46:42.093 14778 17309 I dalvikvm: | group="main" sCount=0 dsCount=0 obj=0x4055e5f8 self=0x361b2809-13 11:46:42.093 14778 17309 I dalvikvm: | sysTid=17309 nice=10 sched=0/0 cgrp=bg_non_interactive handle=335623209-13 11:46:42.093 14778 17309 I dalvikvm: | schedstat=( 1261444095 8805053706 2920 )09-13 11:46:42.093 14778 17309 I dalvikvm: at dalvik.system.NativeStart.run(Native Method)09-13 11:46:42.093 14778 17309 E dalvikvm: VM aborting09-13 11:46:42.093 14778 17309 I dalvikvm: "Binder Thread #3" prio=5 tid=10 NATIVE09-13 11:46:42.093 14778 17309 I dalvikvm: | group="main" sCount=0 dsCount=0 obj=0x4055e5f8 self=0x361b2809-13 11:46:42.093 14778 17309 I dalvikvm: | sysTid=17309 nice=10 sched=0/0 cgrp=bg_non_interactive handle=335623209-13 11:46:42.093 14778 17309 I dalvikvm: | schedstat=( 1261444095 8805053706 2920 )09-13 11:46:42.093 14778 17309 I dalvikvm: at dalvik.system.NativeStart.run(Native Method)
Analysis:
Check the code location. This exception occurs when the mediaprovider server responds to query_transaction, because the memory address that parcel points to is null.
Considering the entire call process, the cursorwindow instance is generated by contentproviderproxy before the binder call. Therefore, the object is generated in the user process and sent to the server. When query_transaction is processed, an exception is thrown because the read cursorwindow instance memory address is null, causing android. process. media exits.
The relevant program code is carefully checked, and no information should be found in the log when memory is insufficient. Therefore, insufficient memory is eliminated. There is no leaked cursor information in the log.
Cause analysis:
When mediaprovider receives an external query request, the process of the other program exits, causing the imemememory binder of the passed cursorwindow to be cleared, therefore, when mediaprovider processes query_transaction, it finds that the memory address of the received imemory object is null, and an exception is thrown to Android. media. exit Process.
The code before calling the binder is as follows:
Contentprovidernative. Java
Final class contentproviderproxy implements icontentprovider {public cursor query (uri url, string [] projection, string selection, string [] selectionargs, string sortorder) throws RemoteException {cursorwindow window = new cursorwindow (false/* window will be used remotely */); // generate an empty cursorwindow instance bulkcursortocursoradaptor adaptor = new bulkcursortocursoradaptor (); ibulkcursor bulkcursor = bulkqueryinternal (URL, projection, selection, selectionargs, sortorder, adaptor. getobserver (), window, Adaptor); If (bulkcursor = NULL) {window. close (); adaptor. close (); return NULL;} return adaptor;} private ibulkcursor bulkqueryinternal (uri url, string [] projection, string selection, string [] selectionargs, string sortorder, icontentobserver observer, cursorwindow window, bulkcursortocursoradaptor Adaptor) throws RemoteException {parcel DATA = parcel. obtain (); parcel reply = parcel. obtain (); data. writeinterfacetoken (icontentprovider. descriptor );... data. writestring (sortorder); data. writestrongbinder (Observer. asbinder (); window. writetoparcel (data, 0); // write the cursorwindow object to parcel... mremote. transAct (icontentprovider. query_transaction, Data, reply, 0); // call databaseutils to the server. readexceptionfromparcel (reply );...
In the query method, call newcursorwindow (false)-> initbuffer (false) to generate an empty cursorwindow. Window. writetoparcel writes the binder object of imemory to parcel.
Cursorwindow. Java
Public void writetoparcel (parcel DEST, int flags) {DeST. writestrongbinder (native_getbinder (); // write the binder object of imemory to parcel DeST. writeint (mstartpos);} bool cursorwindow: initbuffer (bool localonly) {sp <memoryheapbase> heap; heap = new memoryheapbase (mmaxsize, 0, "cursorwindow"); If (heap! = NULL) {mmemory = new memorybase (heap, 0, mmaxsize); If (mmemory! = NULL) {mdata = (uint8_t *) mmemory-> pointer (); If (mdata) {mheader = (window_header_t *) mdata; msize = mmaxsize; // put the window into a clean state clear (); log_window ("created cursorwindow with new memorydealer: mfreeoffset = % d, msize = % d, mmaxsize = % d, mdata = % P ", mfreeoffset, msize, mmaxsize, mdata); Return true ;}} LogE (" cursorwindow heap allocation failed "); // If mdata is empty, because this log does not appear, it must not be empty return false;} else {// If heap memory allocation fails LogE ("failed to create the cursorwindow Heap "); return false ;}}
As none of the above logs appear in the log, the memory allocation is successful.
The following code is called to the server:
Abstract Public class contentprovidernative extends binder implements icontentprovider {public Boolean ontransact (INT code, parcel data, parcel reply, int flags )... switch (CODE) {Case query_transaction: {data. enforceinterface (icontentprovider. descriptor); Uri url = Uri. creator. createfromparcel (data); // string [] projection int num = data. readint (); string [] projection = NULL; If (Num> 0) {projection = new string [num]; for (INT I = 0; I <num; I ++) {projection [I] = data. readstring () ;}// string selection, string [] selectionargs... string selection = data. readstring (); num = data. readint (); string [] selectionargs = NULL; If (Num> 0) {selectionargs = new string [num]; for (INT I = 0; I <num; I ++) {selectionargs [I] = data. readstring () ;}} string sortorder = data. readstring (); icontentobserver observer = icontentobserver. stub. asinterface (data. readstrongbinder (); cursorwindow window = cursorwindow. creator. createfromparcel (data); // This call produces an exception, that is, when the cursorwindow object is read from this parcel, an exception occurs because the memory pointer of this object is null.
The code for recreating cursorwindow from parcel is as follows:
Cursorwindow. Java
Public class cursorwindow extends sqliteclosable implements parcelable {private cursorwindow (parcel source) {// re-create ibinder nativebinder = source from parcel. readstrongbinder (); mstartpos = source. readint (); native_init (nativebinder); // exception here ----} // creates a new empty window. public cursorwindow (Boolean localwindow) {mstartpos = 0; native_init (localwindow);} public static final parcelable. creator <cursorwindow> creator = new parcelable. creator <cursorwindow> () {// rebuilding the cursorwindow instance public cursorwindow createfromparcel (parcel source) {return New cursorwindow (source);} public cursorwindow [] newarray (INT size) from parcel) {return New cursorwindow [size] ;}};
Android_database_cursorwindoextends CPP
Static void native_init_memory (jnienv * ENV, jobject object, jobject memobj) {sp <imemory> memory = interface_cast <imemory> (ibinderforjavaobject (ENV, memobj )); // convert a Java object to an imemory instance if (memory = NULL) {jnithrowexception (ENV, "Java/lang/illegalstateexception", "couldn't get native binder "); return;} cursorwindow * window = new cursorwindow (); If (! Window) {jnithrowexception (ENV, "Java/lang/runtimeexception", "no memory for native window object"); return;} If (! Window-> setmemory (memory) {// jnithrowexception (ENV, "Java/lang/runtimeexception", "no memory in memobj"); Delete window; return ;} log_window ("native_init_memory: numrows = % d, numcolumns = % d, window = % P", window-> getnumrows (), window-> getnumcolumns (), window ); set_window (ENV, object, window );}
Cursorwindow. cpp
Bool cursorwindow: setmemory (const sp <imemory> & memory) {mmemory = memory; mdata = (uint8_t *) memory-> pointer (); If (mdata = NULL) {// apparently, null causes exception return false;} mheader = (window_header_t *) mdata; // make the window read-only ssize_t size = memory-> size (); msize = size; mmaxsize = size; mfreeoffset = size; log_window ("created cursorwindow from existing imemory: mfreeoffset = % d, numrows = % d, numcolumns = % d, msize = % d, mmaxsize = % d, mdata = % P ", mfreeoffset, mheader-> numrows, mheader-> numcolumns, msize, mmaxsize, mdata); Return true ;}
It can be seen that when the binder device wakes up the server to process the query request, the imemory object of the cursorwindow instance sent is invalid, and the object may be cleared due to the caller process crash.