ContentResolver.query流程分析

文章目录

      • 1.Context.getContentResolver()
      • 2.ContentResolver.query()
      • 3.ContentProviderProxy.query()
      • 4.Transport.query()

总结

  • 增删改查ContentProvider时,通过Binder实现
  • ContentProvider在App进程启动时进行实例化,具体时机是在Application.onCreate()执行前
  • 流程图如下:
    ContentResolver.query流程分析_第1张图片

1.Context.getContentResolver()

我们知道Context实现类是ContextImpl,可以看到getContentResolver()返回的是ApplicationContentResolver,相关类图如下:
ContentResolver.query流程分析_第2张图片

// frameworks\base\core\java\android\content\Context.java
public abstract ContentResolver getContentResolver();

// frameworks\base\core\java\android\app\ContextImpl.java
private final ApplicationContentResolver mContentResolver
public ContentResolver getContentResolver() {
   return mContentResolver;
}

private static final class ApplicationContentResolver extends ContentResolver {
    private final ActivityThread mMainThread;

    public ApplicationContentResolver(Context context, ActivityThread mainThread) {
        super(context);
        mMainThread = Objects.requireNonNull(mainThread);
    }

    @Override
    protected IContentProvider acquireProvider(Context context, String auth) {
        return mMainThread.acquireProvider(context,
                ContentProvider.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth), true);
    }
    ......
}

2.ContentResolver.query()

query()有几个重载,最后都执行了第一个,整个逻辑大致如下:从ActivityThread中缓存的mProviderMap中获取对应的ContentProvider,执行其query(),将结果包装成​CursorWrapperInner返回​
在这里插入图片描述

// frameworks\base\core\java\android\content\ContentResolver.java
/**
 * Query the given URI, returning a {@link Cursor} over the result set
 * with support for cancellation.
 *
 * 

For best performance, the caller should follow these guidelines: * *

  • Provide an explicit projection, to prevent reading data from storage * that aren't going to be used. * * Provider must identify which QUERY_ARG_SORT* arguments were honored during * the preparation of the result set by including the respective argument keys * in the {@link Cursor} extras {@link Bundle}. See {@link #EXTRA_HONORED_ARGS} * for details. * * @see #QUERY_ARG_SORT_COLUMNS * @see #QUERY_ARG_SORT_DIRECTION * @see #QUERY_ARG_SORT_COLLATION * * @param uri The URI, using the content:// scheme, for the content to * retrieve. * @param projection A list of which columns to return. Passing null will * return all columns, which is inefficient. * @param queryArgs A Bundle containing additional information necessary for * the operation. Arguments may include SQL style arguments, such * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that * the documentation for each individual provider will indicate * which arguments they support. * @param cancellationSignal A signal to cancel the operation in progress, or null if none. * If the operation is canceled, then {@link OperationCanceledException} will be thrown * when the query is executed. * @return A Cursor object, which is positioned before the first entry. May return * null if the underlying content provider returns null, * or if it crashes. * @see Cursor */ @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"); // 从ApplicationContentResolver构造方法可以看到mWrapped=null try { if (mWrapped != null) { return mWrapped.query(uri, projection, queryArgs, cancellationSignal); } } catch (RemoteException e) { return null; } // 从ActivityThread.acquireProvider()中获取,这里可以看ContentProvider启动流程 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(mContext.getAttributionSource(), 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(mContext.getAttributionSource(), uri, projection, queryArgs, remoteCancellationSignal); } if (qCursor == null) { return null; } // Force query execution. Might fail and throw a runtime exception here. qCursor.getCount(); long durationMillis = SystemClock.uptimeMillis() - startTime; maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs); // Wrap the cursor object into CursorWrapperInner object. final IContentProvider provider = (stableProvider != null) ? stableProvider : acquireProvider(uri); final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider); stableProvider = null; qCursor = null; return wrapper; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. return null; } finally { if (qCursor != null) { qCursor.close(); } if (cancellationSignal != null) { cancellationSignal.setRemote(null); } if (unstableProvider != null) { releaseUnstableProvider(unstableProvider); } if (stableProvider != null) { releaseProvider(stableProvider); } } }
  • 3.ContentProviderProxy.query()

    接下来我们搜索IContentProvider的实现类,发现是ContentProviderNative和ContentProviderProxy

    从这几个类命名和内容,很容易想到和平时写aidl生成的代码很相似,手写了Binder,根据binder调用套路,可以知道调用流程为

    ContentProviderProxy.query() -->ContentProviderNative.onTransact() --> ContentProviderNative.query()

    
    // frameworks\base\core\java\android\content\ContentProviderNative.java
    abstract public class ContentProviderNative extends Binder implements IContentProvider {
        public ContentProviderNative()
        {
            attachInterface(this, descriptor);
        }
        ......
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                throws RemoteException {
                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();
                                }
                            }
                        } else {
                            reply.writeNoException();
                            reply.writeInt(0);
                        }
    
                        return true;
                    }
            ......      
        }
    
        @Override
        public IBinder asBinder()
        {
            return this;
        }
    }
    
    final class ContentProviderProxy implements IContentProvider
    {
        public ContentProviderProxy(IBinder remote)
        {
            mRemote = remote;
        }
    
        @Override
        public IBinder asBinder()
        {
            return mRemote;
        }
    
        @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();
            }
        }
    
    }
    

    4.Transport.query()

    接着搜索谁继承了ContentProviderNative,发现是Transport(Transport为ContentProvider内部类),其query()最终调用了ContentProvider.query(),至此整个ContentResolver.query()流程分析完毕

    // frameworks\base\core\java\android\content\ContentProvider.java
    /**
     * Binder object that deals with remoting.
     *
     * @hide
     */
    // Transport为ContentProvider内部类
    class Transport extends ContentProviderNative {
        ......
        volatile ContentInterface mInterface = ContentProvider.this;
        @Override
        public Cursor query(@NonNull AttributionSource attributionSource, Uri uri,
                @Nullable String[] projection, @Nullable Bundle queryArgs,
                @Nullable ICancellationSignal cancellationSignal) {
            uri = validateIncomingUri(uri);
            uri = maybeGetUriWithoutUserId(uri);
            if (enforceReadPermission(attributionSource, uri)
                    != PermissionChecker.PERMISSION_GRANTED) {
                // The caller has no access to the data, so return an empty cursor with
                // the columns in the requested order. The caller may ask for an invalid
                // column and we would not catch that but this is not a problem in practice.
                // We do not call ContentProvider#query with a modified where clause since
                // the implementation is not guaranteed to be backed by a SQL database, hence
                // it may not handle properly the tautology where clause we would have created.
                if (projection != null) {
                    return new MatrixCursor(projection, 0);
                }
                // Null projection means all columns but we have no idea which they are.
                // However, the caller may be expecting to access them my index. Hence,
                // we have to execute the query as if allowed to get a cursor with the
                // columns. We then use the column names to return an empty cursor.
                Cursor cursor;
                final AttributionSource original = setCallingAttributionSource(
                        attributionSource);
                try {
                    cursor = mInterface.query(
                            uri, projection, queryArgs,
                            CancellationSignal.fromTransport(cancellationSignal));
                } catch (RemoteException e) {
                    throw e.rethrowAsRuntimeException();
                } finally {
                    setCallingAttributionSource(original);
                }
                if (cursor == null) {
                    return null;
                }
                // Return an empty cursor for all columns.
                return new MatrixCursor(cursor.getColumnNames(), 0);
            }
            traceBegin(TRACE_TAG_DATABASE, "query: ", uri.getAuthority());
            final AttributionSource original = setCallingAttributionSource(
                    attributionSource);
            try {
                return mInterface.query(
                        uri, projection, queryArgs,
                        CancellationSignal.fromTransport(cancellationSignal));
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            } finally {
                setCallingAttributionSource(original);
                Trace.traceEnd(TRACE_TAG_DATABASE);
            }
        }
        ......
    }
    

    你可能感兴趣的:(Android源码学习,android)