• ContentResolver.query流程分析



    总结

    • 增删改查ContentProvider时,通过Binder实现
    • ContentProvider在App进程启动时进行实例化,具体时机是在Application.onCreate()执行前
    • 流程图如下:
      在这里插入图片描述

    1.Context.getContentResolver()

    我们知道Context实现类是ContextImpl,可以看到getContentResolver()返回的是ApplicationContentResolver,相关类图如下:
    在这里插入图片描述

    // 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);
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
  • 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();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143

    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);
            }
        }
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  • 相关阅读:
    Hive调优总结(三)-语法和运行参数层面
    用DIV+CSS技术设计我的家乡网站(web前端网页制作课作业)南宁绿城之都
    All in One SEO 插件提取中文描述过短解决方法
    DBeaver报错:can‘t load driver class ‘com.mysql.cj.jdbc.Driver‘
    Python基于Django的电影推荐系统和论坛项目完整源码
    正式发布!Matlab配色神器TheColor
    HTML文本内容 转化为纯文本
    【运维笔记】Docker 部署Kibana-7.4.0(在线Docker版)
    朴素贝叶斯数据分类------
    php+mysql汽车配件管理系统wamp
  • 原文地址:https://blog.csdn.net/wangadping/article/details/128140956