Source Code Analysis of Android Cursor
Keywords:
Database
SQL
Windows
Android
1. Purpose of this paper
Android ContentProvider provides a mechanism for data exchange between processes. and data base The query of the query is the application of this mechanism. So what is Cursor that app gets by querying the database through Uri? Why can we provide data for another process? In this paper, getContentResolver().query(... ) Function as a starting point, a comprehensive analysis of Cursor family relationship class diagram, clarify the mechanism of cross-process communication Cursor.
1.1 Client's Cursor Object
Assuming that there is a Content Provider in process B, process A queries the Content Provider through Uri to get a Cursor. The possible code is as follows:
-
ContentResolver cr = mContext.getContentResolver();
-
Cursor cs = cr.query(uri,null,null,null,null);
In order to know what Cursor really looks like from the above code, we need to look at the way query is invoked. The query function is implemented as follows:
-
public final Cursor query(final Uri uri, String[] projection,
-
String selection, String[] selectionArgs, String sortOrder,
-
CancellationSignal cancellationSignal) {
-
IContentProvider unstableProvider = acquireUnstableProvider(uri);
-
-
try {
-
-
Cursor qCursor;
-
try {
-
qCursor = unstableProvider.query(uri, projection,
-
selection, selectionArgs, sortOrder, remoteCancellationSignal);
-
} catch (DeadObjectException e) {
-
-
}
-
if (qCursor == null) {
-
return null;
-
}
-
-
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
-
stableProvider != null ? stableProvider : acquireProvider(uri));
-
stableProvider = null;
-
return wrapper;
-
} catch (RemoteException e) {
-
-
} finally {
-
-
}
In order to facilitate analysis, the code is omitted. As can be seen from the above code:
1. Cursor returned by query function is a CursorWrapperInner object.
2. CursorWrapper Inner is a wrapper class constructed by the Cursor object returned by the query function of IContentProvider.
So there are two questions:
1.IContentProvider's query function returns Cursor. What is the real object?
2. What role does the CursorWrapperInner class play? Why take Cursor returned from the query function of IContentProvider as a parameter to construct a new CursorWrapperInner?
First, let's look at the class diagram:
From the above class diagram, we can see that:
CursorWrapper Inner is an internal class of ContentResolver, inherited from CrossProcess CursorWrapper. CrossProcess Cursor Wrapper is by name a Cursor wrapper class that implements cross-process communication. This is also verified from the class diagram. CrossProcess Cursor Wrapper inherits from Cursor Wrapper and implements the CrossProcess Cursor interface. CursorWrapper is a wrapper class that implements all the functions of the Cursor interface. It contains a mCursor member variable that points to a Cursor interface, so you can know that this is a proxy mode. CursorWrapper delegates its internal mCursor object to implement all Cursor functional interfaces. CrossProcess Cursor inherits from Cursor, which is mainly used for cross-process communication.
In summary, we can now know that CrossProcess Cursor Wrapper implements all Cursor interfaces, but the completion of these interface functions is delegated to mCursor within its parent class. So what is the real object of mCursor? For the time being, mCursor should be an object that implements CrossProcess Cursor.
Summary: The real object that the client gets is the Cursor WarpprtInner class.
1.2 The true face of Cursor within CursorWrapper
As we know from the previous section, Cursor Wrapper Inner will ultimately delegate Cursor Wrapper to complete the actual functionality through the proxy mode. Now let's look at the real face of mCursor inside CursorWrapper. MCursor comes from the Cursor object returned by the query function of IContentProvider. So what is this Cursor object? Let's look at the implementation of the query function of IContentProvider. IContentProvider is actually a ContentProviderProxy object. It is a proxy class and also a Binder's Bp-side. It packages the parameters of function calls and sends them to ContentProvider Native. Eventually, ContentProvider Native calls the specific functions of ContentProvider.
Content Provider Proxy, Content Provider Native, Content Provider and I ContentProvider have the following relationships:
Following is the query implementation of ContentProviderProxy:
-
public Cursor query(Uri url, String[] projection, String selection,
-
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
-
throws RemoteException {
-
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
-
Parcel data = Parcel.obtain();
-
Parcel reply = Parcel.obtain();
-
try {
-
data.writeInterfaceToken(IContentProvider.descriptor);
-
-
url.writeToParcel(data, 0);
-
int length = 0;
-
if (projection != null) {
-
length = projection.length;
-
}
-
data.writeInt(length);
-
for (int i = 0; i < length; i++) {
-
data.writeString(projection[i]);
-
}
-
data.writeString(selection);
-
if (selectionArgs != null) {
-
length = selectionArgs.length;
-
} else {
-
length = 0;
-
}
-
data.writeInt(length);
-
for (int i = 0; i < length; i++) {
-
data.writeString(selectionArgs[i]);
-
}
-
data.writeString(sortOrder);
-
data.writeStrongBinder(adaptor.getObserver().asBinder());
-
data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
-
-
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
-
-
DatabaseUtils.readExceptionFromParcel(reply);
-
-
if (reply.readInt() != 0) {
-
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
-
adaptor.initialize(d);
-
} else {
-
adaptor.close();
-
adaptor = null;
-
}
-
return adaptor;
-
} catch (RemoteException ex) {
-
adaptor.close();
-
throw ex;
-
} catch (RuntimeException ex) {
-
adaptor.close();
-
throw ex;
-
} finally {
-
data.recycle();
-
reply.recycle();
-
}
-
}
As you can see from the above code, the real object of Cursor returned by the query function is BulkCursorToCursorAdaptor. Within the query function, query requests are passed to the ContentProvider Native end through the transact function. A Parcel will be returned after the transact is executed
Reply. Construct a Bulk Cursor Descriptor from reply. The BulkCursorToCursorAdaptor is then initialized by this BulkCursorDescriptor. A fairly important assignment operation in the Bulk CursorToCursorAdaptor is as follows:
Summary: Questions raised at the beginning of this section: Who is the real face of Cursor inside Cursor Wrapper? Now the answer is: Bulk Cursor To Cursor Adaptor. Named as an adapter, it implements Cursor's functional interface through conversion and calls IBulk Cursor. Since then, the above class diagram is the whole relationship of Cursor in the APP process. So what does IBulk Cursor do? The next section explains.
The mBulk Cursor of the Bulk CursorToCursor Adaptor comes from the return value of ContentProvider Native. To figure out what IBulk Cursor really looks like, look at the implementation of Content Provider Native.
Let's take a look at the real face of Cursor returned by SQLiteDatabase. The following is the final call function of query in SQLiteDatabase. Specific code can refer to SQLiteDatabase. Java Document:
As can be seen from the figure, the mBulkCursor of the member variable of the BulkCursorToCursorAdaptor is an IBuilCursor interface whose real object is actually a BulkCursorProxy. Bulk Cursor Proxy is both a proxy and a Bp-side, which forwards function call requests to the Bn-side Bulk Cursor Native in another process through Binder communication. In the figure, the green line box part runs in the app process, and the red line box part runs in the ContentProvider process.
The real object of mCursor in CursorToBulk Cursor Adaptor is also revealed: SQLiteCursor. It is also known by name that this object is related to SQLLite. It has an internal SQLiteQuery, responsible for database queries and the establishment of Cursor Windows. Cursor Windows is an abstraction of shared memory at the intersection of red and green boxes. There is a mapping in both processes.
Since then, Cursor's analysis has all ended.