ContentProvider运行流程精析

Leo 2021年12月09日 1,290次浏览

概述

ContentProvider用于进程间共享数据,通常使用方法只要我们继承自ContentProvider并重写其中的onCreate,query,insert、update等方法就可使用ContentProvider来进行进程间数据共享,但是,知道怎么使用还是不够的,还需知道它的实现原理。本文以上层应用中调用ContentResolver.query()方法开始,到native层调用数据库相关API获取数据并返回为例进行ContentProvider的执行过程和数据共享原理进行分析。

1.获取ContentResolver

在我们的程序中,调用getContentResolver()就能获得一个ContentResolver对象。我们就一次为开始,进行分析。
getContentResolver一般在我们的自定义的Activity中调用。Activity继承自ContextThemeWrapperContextThemeWrapper又继承自ContextWrappergetContentResolver真正的发生地就是在ContextWrapper中:

@Override
public ContentResolver getContentResolver() {
    return mBase.getContentResolver();
}

直接返回mBase.getContentResolvermBase实际类型为ContextImpl

@Override
public ContentResolver getContentResolver() {
    return mContentResolver;
}

直接返回mContentResolvermContentResolverContextImpl构造函数中直接初始化为ApplicationContentResolver

mContentResolver = new ApplicationContentResolver(this, mainThread);

至此,利用上下文创建了一个ContentResolver对象,并获得返回。

2.利用ContentResolver对象调用query方法

getContentResolver()返回了一个ContentResolver对象,调用query方法:

@Override
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
        @Nullable String[] projection, @Nullable Bundle queryArgs,
        @Nullable CancellationSignal cancellationSignal) {
    Objects.requireNonNull(uri, "uri");

    try {
        if (mWrapped != null) {
            return mWrapped.query(uri, projection, queryArgs, cancellationSignal);
        }
    } catch (RemoteException e) {
        return null;
    }

    IContentProvider unstableProvider = acquireUnstableProvider(uri);
    if (unstableProvider == null) {
        return null;
    }
    IContentProvider stableProvider = null;
    Cursor qCursor = null;
    try {
        long startTime = SystemClock.uptimeMillis();

        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = unstableProvider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        try {
            qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,
                    queryArgs, remoteCancellationSignal);
        } catch (DeadObjectException e) {
            // The remote process has died...  but we only hold an unstable
            // reference though, so we might recover!!!  Let's try!!!!
            // This is exciting!!1!!1!!!!1
            unstableProviderDied(unstableProvider);
            stableProvider = acquireProvider(uri);
            if (stableProvider == null) {
                return null;
            }
            qCursor = stableProvider.query(mPackageName, mAttributionTag, uri, projection,
                    queryArgs, remoteCancellationSignal);
        }
        if (qCursor == null) {
            return null;
        }

ContentResolver有多个query重载方法,最终都会调用到该方法内,主要语句在928行:利用acquireUnstableProvider获取一个IContentProvider对象。利用该IContentProvider对象,调用query方法,IContentProvider是一个IBinder对象,能通过它访问ContentProvider中的服务。此处就是我们即将访问的ContentProvider,即Uri对象的ContentProvider

2.1 acquireUnstableProvider方法的执行

通过前面知道,当前方法所属的对象的实际类型为ApplicationContentResolver,在该类中重写了acquireUnstableProvider方法:

protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c,						 
    ContentProvider.getAuthorityWithoutUserId(auth),						 
    resolveUserIdFromAuthority(auth), false);
}

mMainThread对象为一个ActivityThread类型对象,ActivityThread类管理整个程序的运行,具体执行过程下篇文章分析,本章先到此,知道这一句执行结束,能获得一个IContentProvider即可。

3.IContentProvider.query执行过程

3.0 Cursor继承关系

在继续之前,先来了解一下Cursor类,以及它的继承关系,因为后面的查询过程中,和每个Cursor类息息相关。
image.png

3.1 query执行过程

IContentProvider为一个IBinder对象,本地代理类为ContentProviderProxy,该类为ContentProviderNative的内部类,所以query的执行地为ContentProviderNative.ContentProviderProxy内:

@Override
public Cursor query(@NonNull AttributionSource attributionSource, Uri url,
        @Nullable String[] projection, @Nullable Bundle queryArgs,
        @Nullable ICancellationSignal cancellationSignal)
        throws RemoteException {
    BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    try {
        data.writeInterfaceToken(IContentProvider.descriptor);
        attributionSource.writeToParcel(data, 0);
        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.writeBundle(queryArgs);
        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);
            Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
            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();
    }
}

首先先新建了一个BulkCursorToCursorAdaptor对象,该类继承自Cursor,所以其实最终我们在getContentResolver().query(...)中返回的Cursor实际类型为BulkCursorToCursorAdaptor、而后新建Pacel对象并将参数写入data中,准备进行进程间通信。mRemote为远程ContentProvider的IBinder本地对象,执行这条语句后,接下来过程在远程执行。中间发生了什么,后面讨论,我们先一口气了解完大的过程。当远程执行时,当前线程阻塞,直至远程执行结束。远程执行结束,结果写入reply中。利用reply中数据,新建一个BulkCursorDescription对象,利用该对象初始化BulkCursorToCursorAdaptor对象,接着返回该adaptor对象,一次ContentProvider查询结束。

3.2 mRemote.transact发生了啥

mRemote.transact执行后,进行一次进程间通信码为IContentProvider.QEURY_TRANSACTION的请求。在ContentProvider端,处理请求的类为ContentProviderNative

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    try {
        switch (code) {
            case QUERY_TRANSACTION:
            {
                data.enforceInterface(IContentProvider.descriptor);

                AttributionSource attributionSource = AttributionSource.CREATOR
                        .createFromParcel(data);
                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();
                    }
                }

                 Bundle queryArgs = data.readBundle();
                 IContentObserver observer = IContentObserver.Stub.asInterface(
                         data.readStrongBinder());
                 ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                         data.readStrongBinder());

                 Cursor cursor = query(attributionSource, url, projection, queryArgs,
                         cancellationSignal);
                 if (cursor != null) {
                     CursorToBulkCursorAdaptor adaptor = null;

                     try {
                         adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
                                 getProviderName());
                         cursor = null;

                         BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
                         adaptor = null;

                         reply.writeNoException();
                         reply.writeInt(1);
                         d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                     } finally {
                         // Close cursor if an exception was thrown while constructing the adaptor.
                         if (adaptor != null) {
                             adaptor.close();
                         }
                         if (cursor != null) {
                             cursor.close();
                         }
                     }

从data中取出请求者写入的参数,调用query方法获得一个Cursor,此处Cursor实际类型为SQLiteCursor(后面说具体情况)。利用该Cursor对象新建一个CursorToBulkCursorAdaptor对象,接着利用该CursorToBulkCursorAdaptor对象获取一个BulkCursorDescriptor对象(就是之前从reply中取出来的那货)。将该对象写入reply中。返回reply。此处的问题是:query中发生了啥?adaptor.getBulkCursorDescriptor()中发生了啥?

3.3 query执行过程

此处的qeury调用过程由ContentProvider的内部类Transport类处理:
image.png
重点在圈出来的代码中,调用mInterfacequery方法,mInterface声明类型为ContentInterface,实际类型为ContentProvider.this
所以此处直接调用到我们自定义的ContentProvider中,在自定义ContentProvider中,query有多个继承而来的重载形式,但是最终都会调用到我们自定义的query方法体内。在我们的实现的query方法中,肯定会有一句:SQLiteDataBase db;db.query(...)。继续深入,db.query

public Cursor query(boolean distinct, String table, String[] columns,
        String selection, String[] selectionArgs, String groupBy,
        String having, String orderBy, String limit) {
    return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
            groupBy, having, orderBy, limit, null);
}

在SQLiteDataBase实现中,query有多个实现方法,queryWithFactory也有两个实现方法,但是最终都会调用同一个queryWithFactory:

public Cursor queryWithFactory(CursorFactory cursorFactory,
        boolean distinct, String table, String[] columns,
        String selection, String[] selectionArgs, String groupBy,
        String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
    acquireReference();
    try {
        String sql = SQLiteQueryBuilder.buildQueryString(
                distinct, table, columns, selection, groupBy, having, orderBy, limit);

        return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
                findEditTable(table), cancellationSignal);
    } finally {
        releaseReference();
    }
}

利用SQLiteQueryBuilder类的静态方法buildQueryString方法,将我们以非sql方法查询的查询转为sql,具体过程不再讨论,无非就是根据每个字段,新建一个StringBuilder,往里面不停地加调价、加字段。接着调用rawQueryWithFactory

public Cursor rawQueryWithFactory(
        CursorFactory cursorFactory, String sql, String[] selectionArgs,
        String editTable, CancellationSignal cancellationSignal) {
    acquireReference();
    try {
        SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
                cancellationSignal);
        return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
                selectionArgs);
    } finally {
        releaseReference();
    }
}

(参数对不上?没关系,因为中间有一个重载)新建了一个SQLiteCursorDriver,接着调用该对象query方法。先看下构造函数有没有做什么事:

public final class SQLiteDirectCursorDriver implements SQLiteCursorDriver {
    private final SQLiteDatabase mDatabase;
    private final String mEditTable;
    private final String mSql;
    private final CancellationSignal mCancellationSignal;
    private SQLiteQuery mQuery;

    public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
            CancellationSignal cancellationSignal) {
        mDatabase = db;
        mEditTable = editTable;
        mSql = sql;
        mCancellationSignal = cancellationSignal;
    }

完全没有,就是简单的赋值赋值再赋值。接下来看query方法:

public Cursor query(CursorFactory factory, String[] selectionArgs) {
        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
        final Cursor cursor;
        try {
            query.bindAllArgsAsStrings(selectionArgs);

            if (factory == null) {
                cursor = new SQLiteCursor(this, mEditTable, query);
            } else {
                cursor = factory.newCursor(mDatabase, this, mEditTable, query);
            }
        } catch (RuntimeException ex) {
            query.close();
            throw ex;
        }

        mQuery = query;
        return cursor;
    }

新建了一个SQLiteQuery对象,看一下父类的构造函数

SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
        CancellationSignal cancellationSignalForPrepare) {
    mDatabase = db;
    mSql = sql.trim();

    int n = DatabaseUtils.getSqlStatementType(mSql);
    switch (n) {
        case DatabaseUtils.STATEMENT_BEGIN:
        case DatabaseUtils.STATEMENT_COMMIT:
        case DatabaseUtils.STATEMENT_ABORT:
            mReadOnly = false;
            mColumnNames = EMPTY_STRING_ARRAY;
            mNumParameters = 0;
            break;

        default:
            boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
            SQLiteStatementInfo info = new SQLiteStatementInfo();
            db.getThreadSession().prepare(mSql,
                    db.getThreadDefaultConnectionFlags(assumeReadOnly),
                    cancellationSignalForPrepare, info);
            mReadOnly = info.readOnly;
            mColumnNames = info.columnNames;
            mNumParameters = info.numParameters;
            break;
    }

    if (bindArgs != null && bindArgs.length > mNumParameters) {
        throw new IllegalArgumentException("Too many bind arguments.  "
                + bindArgs.length + " arguments were provided but the statement needs "
                + mNumParameters + " arguments.");
    }

    if (mNumParameters != 0) {
        mBindArgs = new Object[mNumParameters];
        if (bindArgs != null) {
            System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
        }
    } else {
        mBindArgs = null;
    }
}

(我嘞个乖乖,构造函数这么多,一看就不简单)看case就可知道什么意义,query肯定是进default了。重点在19行,获取一个ThreadSession,接着调用prepare方法。该方法的作用就是,再深入一层到native层,调用sqlite3_prepare方法,进行sql语句编译,将sql语句编译成statement,一种sqlite数据库引擎能执行的sqlite程序。在prepare调用中,还传入了一个SQLiteStatementInfo对象,接着23行mColumnNames = infocolumnNames获取了当前查询的表的列名集合。(后面有一处直接就获取列名了,为什么还没查数据库就获取列名了,列名不为空,原因在此)。这儿不再继续挖掘,因为查询数据库的时候会说,和这儿一毛一样,就是调用的方法不同。ok,现在sql已经编译好了。原路返回到上一步的query方法中。

public Cursor query(CursorFactory factory, String[] selectionArgs) {
        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
        final Cursor cursor;
        try {
            query.bindAllArgsAsStrings(selectionArgs);

            if (factory == null) {
                cursor = new SQLiteCursor(this, mEditTable, query);
            } else {
                cursor = factory.newCursor(mDatabase, this, mEditTable, query);
            }
        } catch (RuntimeException ex) {
            query.close();
            throw ex;
        }

        mQuery = query;
        return cursor;
    }

接下来就是利用刚刚创建的SQLiteQuery对象新建一个SQLiteCursor

public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) {
    if (query == null) {
         throw new IllegalArgumentException("query object cannot be null");
     }
     mDriver = driver;
     mEditTable = editTable;
     mColumnNameMap = null;
     mQuery = query;

     mColumns = query.getColumnNames();
 }

就是赋值操作,同时获取了查询的列名集合。
接下来就是沿着调用栈一路返回到3.2节中的onTransact函数中。

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    try {
        switch (code) {
            case QUERY_TRANSACTION:
            {
                data.enforceInterface(IContentProvider.descriptor);

                AttributionSource attributionSource = AttributionSource.CREATOR
                        .createFromParcel(data);
                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();
                    }
                }

                 Bundle queryArgs = data.readBundle();
                 IContentObserver observer = IContentObserver.Stub.asInterface(
                         data.readStrongBinder());
                 ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                         data.readStrongBinder());

                 Cursor cursor = query(attributionSource, url, projection, queryArgs,
                         cancellationSignal);
                 if (cursor != null) {
                     CursorToBulkCursorAdaptor adaptor = null;

                     try {
                         adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
                                 getProviderName());
                         cursor = null;

                         BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
                         adaptor = null;

                         reply.writeNoException();
                         reply.writeInt(1);
                         d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                     } finally {
                         // Close cursor if an exception was thrown while constructing the adaptor.
                         if (adaptor != null) {
                             adaptor.close();
                         }
                         if (cursor != null) {
                             cursor.close();
                         }
                     }

现在我们知道了返回的Cursor为什么实际类型为SQLiteCursor,而且里面的一下重要数据也都清楚了。接着,利用该SQLiteCursor对象新建一个CursorToBulkCursorAdapter对象,构造函数也就是一些赋值操作,不再贴代码。重要的语句是40行,利用该adapter对象获取一个BulkCursorDescriptor。看到这儿了,你肯定有所疑问,onTransactquery调用后返回的Cursor,好像里面并没有进行查询并将结果集写入Cursor啊。没错,现在的query返回的Cursor对象只是一个数据库查询计划,它里面保存着一个将要进行查询的已经编译好的sqlite程序、数据库连接等一系列进行数据库查询需要的数据。它第一次查询数据时是在从Cursor对象中读取数据的时候。而这个的发生地就在adaptor.getBulkCursorDescriptor中。

4.adaptor.getBulkCursorDescriptor执行分析

先上代码:

public BulkCursorDescriptor getBulkCursorDescriptor() {
    synchronized (mLock) {
        throwIfCursorIsClosed();

        BulkCursorDescriptor d = new BulkCursorDescriptor();
        d.cursor = this;
        d.columnNames = mCursor.getColumnNames();
        d.wantsAllOnMoveCalls = mCursor.getWantsAllOnMoveCalls();
        d.count = mCursor.getCount();
        d.window = mCursor.getWindow();
        if (d.window != null) {
            // Acquire a reference to the window because its reference count will be
            // decremented when it is returned as part of the binder call reply parcel.
            d.window.acquireReference();
        }
        return d;
    }
}

简单粗暴,直接新建一个BulkCursorDescriptor对象,接着从mCursor成员变量中获取数据,这个mCursor就是刚刚传入的SQLiteCursor对象。第一步,获取列名集合:

public DragSourceCursor(String value) {
    mValue = value;
}

直接返回mColumns成员变量,而mColumns赋值在前面的构造函数中,从SQLiteQuery对象中获取,SQLiteQuery的列名集合怎么来的?前文已经说过了。到这儿,还是没有进行数据库查询。
接着地9行,从mCursor中获取数据数:

public int getCount() {
    if (mCount == NO_COUNT) {
	fillWindow(0);
    }
    return mCount;
}

看到这个NO_COUNT了吗?这个常量的意义是,还没有进行数据库查询。那么就是还没进行数据库查询,就fillWindow,用什么fill,当然是数据库数据集了:

private void fillWindow(int requiredPos) {
    clearOrCreateWindow(getDatabase().getPath());
    try {
        Preconditions.checkArgumentNonnegative(requiredPos,
                "requiredPos cannot be negative");

        if (mCount == NO_COUNT) {
            mCount = mQuery.fillWindow(mWindow, requiredPos, requiredPos, true);
            mCursorWindowCapacity = mWindow.getNumRows();
            if (SQLiteDebug.NoPreloadHolder.DEBUG_SQL_LOG) {
                Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
            }
        } else {
            int startPos = mFillWindowForwardOnly ? requiredPos : DatabaseUtils
                    .cursorPickFillWindowStartPosition(requiredPos, mCursorWindowCapacity);
            mQuery.fillWindow(mWindow, startPos, requiredPos, false);
        }
    } catch (RuntimeException ex) {
        // Close the cursor window if the query failed and therefore will
        // not produce any results.  This helps to avoid accidentally leaking
        // the cursor window if the client does not correctly handle exceptions
        // and fails to close the cursor.
        closeWindow();
        throw ex;
    }
}

第一步,clearOrCreateWindow,window是什么呢?window就是一块共享内存,用于进程间数据共享,在ContentProvider端将数据写入一块共享内存中,同时将这块共享内存的地址放入返回结果中,在请求端中通过该地址就能访问到这块共享内存,从而实现了数据共享。你可能说,之前不是IBinder来进行数据传送了吗?直接发结果写入IBinder中不就完事了,这么麻烦干嘛?IBinder的确可以共享数据,但是当数据量大时,它就非常耗时,所以,选择用共享内存来进行数据传送,IBinder中只传送共享内存的句柄,从而能高效的传送数据。
接着看下clearOrCreateWindow做了什么:这个方法在AbstractWindowCursor

@UnsupportedAppUsage
protected void clearOrCreateWindow(String name) {
    if (mWindow == null) {
        mWindow = new CursorWindow(name);
    } else {
        mWindow.clear();
    }
}

简单明了,么有就创建,有就清空。而在创建CursorWindow中,会调用native层的CursorWindow类的nativeCreate函数,在native的CursorWindow中会初始化一块共享内存块,最后将该对象返回到java层中的CursorWindow,存于java层的CursorWindow对象的成员变量中,因此就可以通过java层的CursorWindow对象访问到该共享内存块。具体细节不再讨论,可以自行查阅源码。
进入到SQLiteQuery.fillWindow:

int fillWindow(CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
    acquireReference();
    try {
        window.acquireReference();
        try {
            int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
                    window, startPos, requiredPos, countAllRows, getConnectionFlags(),
                    mCancellationSignal);
            return numRows;
        } catch (SQLiteDatabaseCorruptException ex) {
            onCorruption();
            throw ex;
        } catch (SQLiteException ex) {
            Log.e(TAG, "exception: " + ex.getMessage() + "; query: " + getSql());
            throw ex;
        } finally {
            window.releaseReference();
        }
    } finally {
        releaseReference();
    }
}

关键语句6行:getSession()函数,前面在SQLiteProgram中出现过,前面没有具体深入,在这儿深入,前面逻辑一样的。
这个方法位于SQLiteProgram中,调用mDatabase的成员函数getThreadSession方法,mDatabases类型为SQLiteDatabase

protected final SQLiteSession getSession() {
        return mDatabase.getThreadSession();
    }

mThreadSession类型为:ThreadLocal<SQLiteSession>,因此,get方法保证了每个线程中都能获取到自己独有的SQLiteSession。回到上一步:getSession().execteForCursorWindow:

public int executeForCursorWindow(String sql, Object[] bindArgs,
            CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
            int connectionFlags, CancellationSignal cancellationSignal) {
        if (sql == null) {
            throw new IllegalArgumentException("sql must not be null.");
        }
        if (window == null) {
            throw new IllegalArgumentException("window must not be null.");
        }

        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
            window.clear();
            return 0;
        }

        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
        try {
            return mConnection.executeForCursorWindow(sql, bindArgs,
                    window, startPos, requiredPos, countAllRows,
                    cancellationSignal); // might throw
        } finally {
            releaseConnection(); // might throw
        }
    }

首先判断是不是执行特殊sql语句:

private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
            CancellationSignal cancellationSignal) {
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
        }

        final int type = DatabaseUtils.getSqlStatementType(sql);
        switch (type) {
            case DatabaseUtils.STATEMENT_BEGIN:
                beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
                        cancellationSignal);
                return true;

            case DatabaseUtils.STATEMENT_COMMIT:
                setTransactionSuccessful();
                endTransaction(cancellationSignal);
                return true;

            case DatabaseUtils.STATEMENT_ABORT:
                endTransaction(cancellationSignal);
                return true;
        }
        return false;
    }

当sql是开启事务、提交事务、abort时,调用相应的处理函数。不再深入。回到上一步:acquireConnection:

private void acquireConnection(String sql, int connectionFlags,
            CancellationSignal cancellationSignal) {
        if (mConnection == null) {
            assert mConnectionUseCount == 0;
            mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
                    cancellationSignal); // might throw
            mConnectionFlags = connectionFlags;
        }
        mConnectionUseCount += 1;
    }

从连接池中获取一个连接,mConnectionPool类型为SQLiteConnection:

public SQLiteConnection acquireConnection(String sql, int connectionFlags,
            CancellationSignal cancellationSignal) {
        SQLiteConnection con = waitForConnection(sql, connectionFlags, cancellationSignal);
        synchronized (mLock) {
            if (mIdleConnectionHandler != null) {
                mIdleConnectionHandler.connectionAcquired(con);
            }
        }
        return con;
    }

直接调用waitForConnection

private SQLiteConnection waitForConnection(String sql, int connectionFlags,
            CancellationSignal cancellationSignal) {
        final boolean wantPrimaryConnection =
                (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;

        final ConnectionWaiter waiter;
        final int nonce;
        synchronized (mLock) {
            throwIfClosedLocked();

            // Abort if canceled.
            if (cancellationSignal != null) {
                cancellationSignal.throwIfCanceled();
            }

            // Try to acquire a connection.
            SQLiteConnection connection = null;
            if (!wantPrimaryConnection) {
                connection = tryAcquireNonPrimaryConnectionLocked(
                        sql, connectionFlags); // might throw
            }
            if (connection == null) {
                connection = tryAcquirePrimaryConnectionLocked(connectionFlags); // might throw
            }
            if (connection != null) {
                return connection;
            }

此处tryAcquireNonPrimaryConnectionLockedtryAcquirePrimaryConnectionLocked最终都会调用openConnectionLocked

private SQLiteConnection tryAcquireNonPrimaryConnectionLocked(
        String sql, int connectionFlags) {
    // Try to acquire the next connection in the queue.
    SQLiteConnection connection;
    final int availableCount = mAvailableNonPrimaryConnections.size();
    if (availableCount > 1 && sql != null) {
        // If we have a choice, then prefer a connection that has the
        // prepared statement in its cache.
        for (int i = 0; i < availableCount; i++) {
            connection = mAvailableNonPrimaryConnections.get(i);
            if (connection.isPreparedStatementInCache(sql)) {
                mAvailableNonPrimaryConnections.remove(i);
                finishAcquireConnectionLocked(connection, connectionFlags); // might throw
                return connection;
            }
        }
    }
    if (availableCount > 0) {
        // Otherwise, just grab the next one.
        connection = mAvailableNonPrimaryConnections.remove(availableCount - 1);
        finishAcquireConnectionLocked(connection, connectionFlags); // might throw
        return connection;
    }

    // Expand the pool if needed.
    int openConnections = mAcquiredConnections.size();
    if (mAvailablePrimaryConnection != null) {
        openConnections += 1;
    }
    if (openConnections >= mMaxConnectionPoolSize) {
        return null;
    }
    connection = openConnectionLocked(mConfiguration,
            false /*primaryConnection*/); // might throw
    finishAcquireConnectionLocked(connection, connectionFlags); // might throw
    return connection;
}

进入openConnectionLocked:

private SQLiteConnection openConnectionLocked(SQLiteDatabaseConfiguration configuration,
        boolean primaryConnection) {
    final int connectionId = mNextConnectionId++;
    return SQLiteConnection.open(this, configuration,
            connectionId, primaryConnection); // might throw
}

直接调用SQLiteConnection的静态成员函数open

static SQLiteConnection open(SQLiteConnectionPool pool,
        SQLiteDatabaseConfiguration configuration,
        int connectionId, boolean primaryConnection) {
    SQLiteConnection connection = new SQLiteConnection(pool, configuration,
            connectionId, primaryConnection);
    try {
        connection.open();
        return connection;
    } catch (SQLiteException ex) {
        connection.dispose(false);
        throw ex;
    }
}

5行,调用native层的nativeOpen函数,SQLiteConnection对象的navite层类为android_database_SQLiteConnection

private void open() {
       final String file = mConfiguration.path;
       final int cookie = mRecentOperations.beginOperation("open", null, null);
       try {
           mConnectionPtr = nativeOpen(file, mConfiguration.openFlags,
                   mConfiguration.label,
                   NoPreloadHolder.DEBUG_SQL_STATEMENTS, NoPreloadHolder.DEBUG_SQL_TIME,
                   mConfiguration.lookasideSlotSize, mConfiguration.lookasideSlotCount);
       } catch (SQLiteCantOpenDatabaseException e) {
           final StringBuilder message = new StringBuilder("Cannot open database '")
                   .append(file).append('\'');

           try {
               // Try to diagnose for common reasons. If something fails in here, that's fine;
               // just swallow the exception.

               final Path path = FileSystems.getDefault().getPath(file);
               final Path dir = path.getParent();

               if (!Files.isDirectory(dir)) {
                   message.append(": Directory ").append(dir).append(" doesn't exist");
               } else if (!Files.exists(path)) {
                   message.append(": File ").append(path).append(" doesn't exist");
               } else if (!Files.isReadable(path)) {
                   message.append(": File ").append(path).append(" is not readable");
               } else if (Files.isDirectory(path)) {
                   message.append(": Path ").append(path).append(" is a directory");
               } else {
                   message.append(": Unknown reason");
               }
           } catch (Throwable th) {
               message.append(": Unknown reason; cannot examine filesystem: ")
                       .append(th.getMessage());
           }
           throw new SQLiteCantOpenDatabaseException(message.toString(), e);
       } finally {
           mRecentOperations.endOperation(cookie);
       }
       setPageSize();
       setForeignKeyModeFromConfiguration();
       setWalModeFromConfiguration();
       setJournalSizeLimit();
       setAutoCheckpointInterval();
       setLocaleFromConfiguration();
       setCustomFunctionsFromConfiguration();
       executePerConnectionSqlFromConfiguration(0);
   }
static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
       jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
       jint lookasideCnt) {
   int sqliteFlags;
   if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
       sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
   } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
       sqliteFlags = SQLITE_OPEN_READONLY;
   } else {
       sqliteFlags = SQLITE_OPEN_READWRITE;
   }

   const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
   String8 path(pathChars);
   env->ReleaseStringUTFChars(pathStr, pathChars);

   const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
   String8 label(labelChars);
   env->ReleaseStringUTFChars(labelStr, labelChars);

   sqlite3* db;
   int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
   if (err != SQLITE_OK) {
       throw_sqlite3_exception_errcode(env, err, "Could not open database");
       return 0;
   }

   if (lookasideSz >= 0 && lookasideCnt >= 0) {
       int err = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL, lookasideSz, lookasideCnt);
       if (err != SQLITE_OK) {
           ALOGE("sqlite3_db_config(..., %d, %d) failed: %d", lookasideSz, lookasideCnt, err);
           throw_sqlite3_exception(env, db, "Cannot set lookaside");
           sqlite3_close(db);
           return 0;
       }
   }

   // Check that the database is really read/write when that is what we asked for.
   if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
       throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
       sqlite3_close(db);
       return 0;
   }

   // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
   err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
   if (err != SQLITE_OK) {
       throw_sqlite3_exception(env, db, "Could not set busy timeout");
       sqlite3_close(db);
       return 0;
   }

   // Register custom Android functions.
   err = register_android_functions(db, UTF16_STORAGE);
   if (err) {
       throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
       sqlite3_close(db);
       return 0;
   }

   // Create wrapper object.
   SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);

   // Enable tracing and profiling if requested.
   if (enableTrace) {
       sqlite3_trace(db, &sqliteTraceCallback, connection);
   }
   if (enableProfile) {
       sqlite3_profile(db, &sqliteProfileCallback, connection);
   }

   ALOGV("Opened connection %p with label '%s'", db, label.string());
   return reinterpret_cast<jlong>(connection);

21行,声明一个sqlite3连接指针,22行,直接调用sqlite3 API 函数sqlite3_open_v2,打开了一个数据库并建立了连接,接着29、46、54行分别调用sqlite3 API 函数进行一些数据库配置。到此,数据库已经成功打开(不出意外的话)。
返回到SQLiteSession.executeForCursorWindow中:

try {
    return mConnection.executeForCursorWindow(sql, bindArgs,
            window, startPos, requiredPos, countAllRows,
            cancellationSignal); // might throw
} finally {
    releaseConnection(); // might throw

调用SQLiteConnection的executeForCursorWindow函数:

public int executeForCursorWindow(String sql, Object[] bindArgs,
        CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
        CancellationSignal cancellationSignal) {
    if (sql == null) {
        throw new IllegalArgumentException("sql must not be null.");
    }
    if (window == null) {
        throw new IllegalArgumentException("window must not be null.");
    }
    window.acquireReference();
    try {
        int actualPos = -1;
        int countedRows = -1;
        int filledRows = -1;
        final int cookie = mRecentOperations.beginOperation("executeForCursorWindow",
                sql, bindArgs);
        try {
            final PreparedStatement statement = acquirePreparedStatement(sql);
            try {
                throwIfStatementForbidden(statement);
                bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
                 attachCancellationSignal(cancellationSignal);
                 try {
                     final long result = nativeExecuteForCursorWindow(
                             mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
                             startPos, requiredPos, countAllRows);
                     actualPos = (int)(result >> 32);
                     countedRows = (int)result;
                     filledRows = window.getNumRows();
                     window.setStartPosition(actualPos);
                     return countedRows;
                 } finally {
                     detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
             }
         } catch (RuntimeException ex) {
             mRecentOperations.failOperation(cookie, ex);
             throw ex;
         } finally {
             if (mRecentOperations.endOperationDeferLog(cookie)) {
                 mRecentOperations.logOperation(cookie, "window='" + window
                         + "', startPos=" + startPos
                         + ", actualPos=" + actualPos
                         + ", filledRows=" + filledRows
                         + ", countedRows=" + countedRows);
             }
         }
     } finally {
         window.releaseReference();
     }
 }

关键点在942行,调用native层nativeExecuteForCursorWindow:到android_database_SQLiteConnection中找这个函数:
这儿直接贴出源码,在源码的三个关键位置已经做了注释

static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
        jlong connectionPtr, jlong statementPtr, jlong windowPtr,
        jint startPos, jint requiredPos, jboolean countAllRows) {
    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
    CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);

    status_t status = window->clear();
    if (status) {
        String8 msg;
        msg.appendFormat("Failed to clear the cursor window, status=%d", status);
        throw_sqlite3_exception(env, connection->db, msg.string());
        return 0;
    }

    int numColumns = sqlite3_column_count(statement);
    status = window->setNumColumns(numColumns);
    if (status) {
        String8 msg;
        msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
                numColumns, status);
        throw_sqlite3_exception(env, connection->db, msg.string());
        return 0;
    }

    int retryCount = 0;
    int totalRows = 0;
    int addedRows = 0;
    bool windowFull = false;
    bool gotException = false;
    while (!gotException && (!windowFull || countAllRows)) {


    //调用sqlite3 库函数sqlite3_step,单步执行sqlite程序,当一行数据获取结束,返回SQLITE_ROW,获取返回错误码
        int err = sqlite3_step(statement);
        //SQLITE_ROW已经表示获取到一行数据了,可以调用相应的库函数拿去数据了
    if (err == SQLITE_ROW) {
            LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
            retryCount = 0;
            totalRows += 1;

            // Skip the row if the window is full or we haven't reached the start position yet.
            if (startPos >= totalRows || windowFull) {
                continue;
            }
            //自定义函数,用于拿去数据并写入到共享内存块window中
            CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
            if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) {
                // We filled the window before we got to the one row that we really wanted.
                // Clear the window and start filling it again from here.
                // TODO: Would be nicer if we could progressively replace earlier rows.
                window->clear();
                window->setNumColumns(numColumns);
                startPos += addedRows;
                addedRows = 0;
                cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
            }

            if (cpr == CPR_OK) {
                addedRows += 1;
            } else if (cpr == CPR_FULL) {
                windowFull = true;
            } else {
                gotException = true;
            }
        } else if (err == SQLITE_DONE) {
            // All rows processed, bail
            LOG_WINDOW("Processed all rows");
            break;
        } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
            // The table is locked, retry
            LOG_WINDOW("Database locked, retrying");
            if (retryCount > 50) {
                ALOGE("Bailing on database busy retry");
                throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
                gotException = true;
            } else {
                // Sleep to give the thread holding the lock a chance to finish
                usleep(1000);
                retryCount++;
            }
        } else {
            throw_sqlite3_exception(env, connection->db);
            gotException = true;
        }
    }

    LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
            "to the window in %d bytes",
            statement, totalRows, addedRows, window->size() - window->freeSpace());
    sqlite3_reset(statement);

    // Report the total number of rows on request.
    if (startPos > totalRows) {
        ALOGE("startPos %d > actual rows %d", startPos, totalRows);
    }
    if (totalRows > 0 && addedRows == 0) {
        String8 msg;
        msg.appendFormat("Row too big to fit into CursorWindow requiredPos=%d, totalRows=%d",
                requiredPos, totalRows);
        throw_sqlite3_exception(env, SQLITE_TOOBIG, NULL, msg.string());
        return 0;
    }

    jlong result = jlong(startPos) << 32 | jlong(totalRows);
    return result;
}

接着看看copyRow的实现:

 static CopyRowResult copyRow(JNIEnv* env, CursorWindow* window,
    sqlite3_stmt* statement, int numColumns, int startPos, int addedRows) {
// Allocate a new field directory for the row.
status_t status = window->allocRow();
if (status) {
    LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d, error=%d",
            startPos, addedRows, status);
    return CPR_FULL;
}
// Pack the row into the window.
CopyRowResult result = CPR_OK;
for (int i = 0; i < numColumns; i++) {
    int type = sqlite3_column_type(statement, i);
    if (type == SQLITE_TEXT) {
        // TEXT data
        const char* text = reinterpret_cast<const char*>(
                sqlite3_column_text(statement, i));
        // SQLite does not include the NULL terminator in size, but does
        // ensure all strings are NULL terminated, so increase size by
        // one to make sure we store the terminator.
        size_t sizeIncludingNull = sqlite3_column_bytes(statement, i) + 1;
        status = window->putString(addedRows, i, text, sizeIncludingNull);
        if (status) {
            LOG_WINDOW("Failed allocating %zu bytes for text at %d,%d, error=%d",
                    sizeIncludingNull, startPos + addedRows, i, status);
            result = CPR_FULL;
            break;
        }
        LOG_WINDOW("%d,%d is TEXT with %zu bytes",
                startPos + addedRows, i, sizeIncludingNull);
    } else if (type == SQLITE_INTEGER) {
        // INTEGER data
        int64_t value = sqlite3_column_int64(statement, i);
        status = window->putLong(addedRows, i, value);
        if (status) {
            LOG_WINDOW("Failed allocating space for a long in column %d, error=%d",
                    i, status);
            result = CPR_FULL;
            break;
        }
        LOG_WINDOW("%d,%d is INTEGER %" PRId64, startPos + addedRows, i, value);
    } else if (type == SQLITE_FLOAT) {
        // FLOAT data
        double value = sqlite3_column_double(statement, i);
        status = window->putDouble(addedRows, i, value);
        if (status) {
            LOG_WINDOW("Failed allocating space for a double in column %d, error=%d",
                    i, status);
            result = CPR_FULL;
            break;
        }
        LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
    } else if (type == SQLITE_BLOB) {
        // BLOB data
        const void* blob = sqlite3_column_blob(statement, i);
        size_t size = sqlite3_column_bytes(statement, i);
        status = window->putBlob(addedRows, i, blob, size);
        if (status) {
            LOG_WINDOW("Failed allocating %zu bytes for blob at %d,%d, error=%d",
                    size, startPos + addedRows, i, status);
            result = CPR_FULL;
            break;
        }
        LOG_WINDOW("%d,%d is Blob with %zu bytes",
                startPos + addedRows, i, size);
    } else if (type == SQLITE_NULL) {
        // NULL field
        status = window->putNull(addedRows, i);
        if (status) {
            LOG_WINDOW("Failed allocating space for a null in column %d, error=%d",
                    i, status);
            result = CPR_FULL;
            break;
        }
        LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
    } else {
        // Unknown data
        ALOGE("Unknown column type when filling database window");
        throw_sqlite3_exception(env, "Unknown column type when filling window");
        result = CPR_ERROR;
        break;
    }
}
// Free the last row if if was not successfully copied.
if (result != CPR_OK) {
    window->freeLastRow();
}
return result;
}

逻辑是,对于一行中的每一列,先利用sqlite3_column_type库函数获取该列的数据类型,对于不同的数据类型,调用sqlite3_column_(type)获取数据,在将该输入写入到共享内存window中。
到此,所有流程都已经分析结束了,其中有很多细节都没有分析,比如最后这儿,向window中写入数据时是怎么实现的等等,这些读者可以自行查看源码了解。