Android ContentProvider

作者: lbtrace | 来源:发表于2018-08-11 21:34 被阅读16次

    本文基于Android 7.0,涉及的主要源码:
    aosp/frameworks/base/core/java/android/app/ContextImpl.java
    aosp/frameworks/base/core/java/android/app/ActivityThread.java
    aosp/frameworks/base/core/java/android/app/ActivityManagerNative.java
    aosp/frameworks/base/core/java/android/app/ApplicationThreadNative.java

    aosp/frameworks/base/core/java/android/content/ContentResolver.java
    aosp/frameworks/base/core/java/android/content/ContentProvider.java
    aosp/frameworks/base/core/java/android/content/ContentProviderNative.java

    aosp/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    aosp/frameworks/base/core/java/android/database/AbstractCursor.java
    aosp/frameworks/base/core/java/android/database/MatrixCursor.java
    aosp/frameworks/base/core/java/android/database/CursorWindow.java
    aosp/frameworks/base/core/java/android/database/BulkCursorNative.java
    aosp/frameworks/base/core/java/android/database/CursorToBulkCursorAdaptor.java
    aosp/frameworks/base/core/java/android/database/BulkCursorDescriptor.java
    aosp/frameworks/base/core/java/android/database/BulkCursorToCursorAdaptor.java
    aosp/frameworks/base/core/java/android/database/DatabaseUtils.java
    aosp/frameworks/base/core/jni/android_database_CursorWindow.cpp
    aosp/frameworks/base/libs/androidfw/CursorWindow.cpp

    类图

    • ContentResolver
      • 应用使用该类访问ContentProvider
    • ContentProviderProxy
      • ContentProvider代理对象
    • ContentProviderNative
      • ContentProvider本地对象
    • Transport
      • 实现了ContentProviderNative
    • ContentProvider
      • 用于应用间共享数据

    通过ContentResolver获取ContentProviderProxy对象

    下面从ContextImplgetContentResolver()开始分析

    public ContentResolver getContentResolver() {
        return mContentResolver;
    }
    

    这里mContentResolver是一个ApplicationContentResolver类型的引用,它是在ContextImpl构造函数中创建的,下面看ApplicationContentResolverquery()

    public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
            @Nullable String[] projection, @Nullable String selection,
            @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return query(uri, projection, selection, selectionArgs, sortOrder, null);
    }
    
    public final @Nullable Cursor query(final @RequiresPermission.Read @NonNullUri uri,
            @Nullable String[] projection, @Nullable String selection,
            @Nullable String[] selectionArgs, @Nullable String sortOrder,
            @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        // 获取unstableProvider代理,unstableProvider为ContentProviderProxy对象
        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 {
                // 通过Binder IPC向ContentProvider查询信息
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
                ......
            }
            ......
        }
        ......
    }
    
    protected IContentProvider acquireUnstableProvider(Context c, String auth){
        // 调用ActivityThread的acquireProvider
        // ContentProvider.getAuthorityWithoutUserId(auth)通常返回auth
        // resolveUserIdFromAuthority(auth)通常返回0
        return mMainThread.acquireProvider(c,
                ContentProvider.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth), false);
    }
    
    • unstableProvider
      • 当ContentProvider宿主进程死亡时,系统会通知ContentProvider客户端进程
    • stableProvider
      • 当ContentProvider宿主进程死亡时
        • ContentProviderConnection存在时,系统会杀死非persistent的ContentProvider客户端进程
        • ContentProviderConnection移除时,系统不会杀ContentProvider客户端进程
          下面看ActivityThreadacquireProvider()的实现
    public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        // 查询缓存的Provider代理
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;
        }
        // There is a possible race here.  Another thread may try to acquire
        // the same provider at the same time.  When this happens, we want to ensure
        // that the first one wins.
        // Note that we cannot hold the lock while acquiring and installing the
        // provider since it might take a long time to run and it could also potentially
        // be re-entrant in the case where the provider is in the same process.
        IActivityManager.ContentProviderHolder holder = null;
        try {
            // 非system_server进程ActivityManagerNative.getDefault()返回ActivityManagerProxy对象
            // 向ActivityManagerService查询ContentProvider
            // getApplicationThread()返回ApplicationThread对象
            // userId为auth所属用户userId,通常为0
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            return null;
        }
        // Install provider will increment the reference count for us, and break
        // any ties in the race.
        // 系统进程(uid == 0 || uid == SYSTEM_UID)中holder.noReleaseNeeded为true
        // 普通客户端进程holder.noReleaseNeeded为false
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }
    

    下面首先看acquireExistingProvider()的实现

    public final IContentProvider acquireExistingProvider(
            Context c, String auth, int userId, boolean stable) {
        synchronized (mProviderMap) {
            final ProviderKey key = new ProviderKey(auth, userId);
            final ProviderClientRecord pr = mProviderMap.get(key);
            if (pr == null) {
                return null;
            }
            IContentProvider provider = pr.mProvider;
            // jBinder为BinderProxy或者Binder对象
            IBinder jBinder = provider.asBinder();
            // 查询ContentProvider宿主进程是否活着
            if (!jBinder.isBinderAlive()) {
                // The hosting process of the provider has died; we can't
                // use this one.
                Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
                        + ": existing object's process dead");
                // 处理ContentProvider宿主进程死亡的情况
                handleUnstableProviderDiedLocked(jBinder, true);
                return null;
            }
            // Only increment the ref count if we have one.  If we don't then the
            // provider is not reference counted and never needs to be released.
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                // 非ContentProvider宿主进程,增加ContentProvider引用计数
                incProviderRefLocked(prc, stable);
            }
            return provider;
        }
    }
    
    • ProviderKey
      • 保存authorith以及userId
    • ProviderClientRecord
      • 保存Provider信息(在ContentProvider宿主进程及客户端均使用)

    这里假定acquireExistingProvider()返回null,下面看getContentProvider()的实现

    // caller为ApplicationThread对象继承自ApplicationThreadNative
    // name为authority, 这里stable为false
    public ContentProviderHolder getContentProvider(IApplicationThread caller,
            String name, int userId, boolean stable) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(name);
        data.writeInt(userId);
        data.writeInt(stable ? 1 : 0);
        // 向ActivityManagerService查询ContentProvider,这里等待reply
        mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        ContentProviderHolder cph = null;
        if (res != 0) {
            // 创建ContentProviderHolder
            cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
        }
        data.recycle();
        reply.recycle();
        return cph;
    }
    

    getContentProvider()是个Binder IPC,下面直接看ActivityManagerService处理请求

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        ......
        case GET_CONTENT_PROVIDER_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            // app为ApplicationThreadProxy对象
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            // name为authorith字符串
            String name = data.readString();
            // userId为ContentProvider所属用户id,通常为0
            int userId = data.readInt();
            // stable这里为false
            boolean stable = data.readInt() != 0;
            ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
            reply.writeNoException();
            if (cph != null) {
                reply.writeInt(1);
                cph.writeToParcel(reply, 0);
            } else {
                reply.writeInt(0);
            }
            return true;
        }
        ......
        }
        ......
    }
    
    public final ContentProviderHolder getContentProvider(
            IApplicationThread caller, String name, int userId, boolean stable) {
        // Isolated进程不允许获取ContentProvider    
        enforceNotIsolatedCaller("getContentProvider");
        if (caller == null) {
            String msg = "null IApplicationThread when getting content provider "
                    + name;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
        // with cross-user grant.
        return getContentProviderImpl(caller, name, null, stable, userId);
    }
    
    private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {
        // token为null
        ContentProviderRecord cpr;
        // 代表ContentProvider与客户端之间的连接
        ContentProviderConnection conn = null;
        // 持有特定ContentProvider信息
        ProviderInfo cpi = null;
    
        synchronized(this) {
            long startTime = SystemClock.uptimeMillis();
            ProcessRecord r = null;
            if (caller != null) {
                // 根据ApplicationThreadProxy查找ProcessRecord
                r = getRecordForAppLocked(caller);
                if (r == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                          + " (pid=" + Binder.getCallingPid()
                          + ") when getting content provider " + name);
                }
            }
            boolean checkCrossUser = true;
            checkTime(startTime, "getContentProviderImpl: getProviderByName");
            // First check if this content provider has been published...
            // 检查目标ContentProvider是否已经发布,cpr不为null也并不意味着ContentProvider已经发布
            cpr = mProviderMap.getProviderByName(name, userId);
            ......
            boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
            if (providerRunning) {
                // ContentProvider已经发布
                cpi = cpr.info;
                String msg;
                ......
                if (r != null && cpr.canRunHere(r)) {
                    // ContentProvider能够运行在调用者进程,例如:
                    // 1) 多进程ContentProvider同时调用者与ContentProvider宿主进程uid相同
                    // This provider has been published or is in the process
                    // of being published...  but it is also allowed to run
                    // in the caller's process, so don't make a connection
                    // and just let the caller instantiate its own instance.
                    ContentProviderHolder holder = cpr.newHolder(null);
                    // don't give caller the provider object, it needs
                    // to make its own.
                    // holder.provider为null,调用者自己实例化ContentProvider
                    holder.provider = null;
                    return holder;
                }
                final long origId = Binder.clearCallingIdentity();
                checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
                // In this case the provider instance already exists, so we can
                // return it right away.
                // 增加ContentProvider引用计数
                conn = incProviderCountLocked(r, cpr, token, stable);
                if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
                    if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                        // If this is a perceptible app accessing the provider,
                        // make sure to count it as being accessed and thus
                        // back up on the LRU list.  This is good because
                        // content providers are often expensive to start.
                        checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
                        // ContentProvider客户端为percetible app,调整
                        // ContentProvider宿主进程及关联进程在LRU链表中的位置
                        updateLruProcessLocked(cpr.proc, false, null);
                        checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
                    }
                }
                checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                final int verifiedAdj = cpr.proc.verifiedAdj;
                // 更新ContentProvider宿主进程状态及oomadj值
                boolean success = updateOomAdjLocked(cpr.proc);
                ......
                if (!success) {
                    // ContentProvider宿主进程死亡
                    // Uh oh...  it looks like the provider's process
                    // has been killed on us.  We need to wait for a new
                    // process to be started, and make sure its death
                    // doesn't kill our process.
                    Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                            + " is crashing; detaching " + r);
                    // 减少引用计数,如果计数为0,断开连接避免客户进程被杀
                    boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
                    checkTime(startTime, "getContentProviderImpl: before appDied");
                    appDiedLocked(cpr.proc);
                    checkTime(startTime, "getContentProviderImpl: after appDied");
                    if (!lastRef) {
                        // This wasn't the last ref our process had on
                        // the provider...  we have now been killed, bail.
                        return null;
                    }
                    providerRunning = false;
                    conn = null;
                } else {
                    cpr.proc.verifiedAdj = cpr.proc.setAdj;
                }
                Binder.restoreCallingIdentity(origId);
            }
            if (!providerRunning) {
                // ContentProvider没有运行
                try {
                    checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
                    // 向PackageManagerService查询ProviderInfo
                    cpi = AppGlobals.getPackageManager().
                        resolveContentProvider(name,
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
                    checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
                } catch (RemoteException ex) {
                }
                if (cpi == null) {
                    return null;
                }
                // If the provider is a singleton AND
                // (it's a call within the same user || the provider is a
                // privileged app)
                // Then allow connecting to the singleton provider
                // 检查ContentProvider是否为单例(多用户共享)
                boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                        cpi.name, cpi.flags)
                        && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
                if (singleton) {
                    userId = UserHandle.USER_SYSTEM;
                }
                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
                checkTime(startTime, "getContentProviderImpl: got app info for user");
                String msg;
                checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
                // 检查客户端是否有权限访问ContentProvider
                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
                        != null) {
                    throw new SecurityException(msg);
                }
                checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
                // system准备好之前不能运行非system进程ContentProvider
                if (!mProcessesReady
                        && !cpi.processName.equals("system")) {
                    // If this content provider does not run in the system
                    // process, and the system is not yet ready to run other
                    // processes, then fail fast instead of hanging.
                    throw new IllegalArgumentException(
                            "Attempt to launch content provider before system ready");
                }
                // Make sure that the user who owns this provider is running.  If not,
                // we don't want to allow it to run.
                if (!mUserController.isUserRunningLocked(userId, 0)) {
                    Slog.w(TAG, "Unable to launch app "
                            + cpi.applicationInfo.packageName + "/"
                            + cpi.applicationInfo.uid + " for provider "
                            + name + ": user " + userId + " is stopped");
                    return null;
                }
                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
                // 根据组件名及userId获取ContentProviderRecord
                cpr = mProviderMap.getProviderByClass(comp, userId);
                checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
                final boolean firstClass = cpr == null;
                if (firstClass) {
                    // 需要创建ContentProviderRecord
                    final long ident = Binder.clearCallingIdentity();
                    // If permissions need a review before any of the app components can run,
                    // we return no provider and launch a review activity if the calling app
                    // is in the foreground.
                    if (Build.PERMISSIONS_REVIEW_REQUIRED) {
                        if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
                            return null;
                        }
                    }
                    try {
                        checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
                        // 从PackageManagerService获取ApplicationInfo
                        ApplicationInfo ai =
                            AppGlobals.getPackageManager().
                                getApplicationInfo(
                                        cpi.applicationInfo.packageName,
                                        STOCK_PM_FLAGS, userId);
                        checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
                        if (ai == null) {
                            Slog.w(TAG, "No package info for content provider "
                                    + cpi.name);
                            return null;
                        }
                        ai = getAppInfoForUser(ai, userId);
                        // 创建ContentProviderRecord
                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                    } catch (RemoteException ex) {
                        // pm is in same process, this will never happen.
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                }
                checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
                if (r != null && cpr.canRunHere(r)) {
                    // ContentProvider能够运行在调用者进程,例如:
                    // 1) 调用者是ContentProvider宿主自身
                    // 2) 多进程ContentProvider同时调用者与ContentProvider宿主进程uid相同
                    // 这里无需设置holder.provider为null,ContentProviderRecord创建后成员provider默认为null
                    return cpr.newHolder(null);
                }
                if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
                            + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
                            + cpr.info.name + " callers=" + Debug.getCallers(6));
                // This is single process, and our app is now connecting to it.
                // See if we are already in the process of launching this
                // provider.
                final int N = mLaunchingProviders.size();
                int i;
                for (i = 0; i < N; i++) {
                    if (mLaunchingProviders.get(i) == cpr) {
                        break;
                    }
                }
                // If the provider is not already being launched, then get it
                // started.
                if (i >= N) {
                    final long origId = Binder.clearCallingIdentity();
                    try {
                        // Content provider is now in use, its package can't be stopped.
                        try {
                            checkTime(startTime, "getContentProviderImpl: before set stopped state");
                            // 设置ContentProvider包的状态
                            AppGlobals.getPackageManager().setPackageStoppedState(
                                    cpr.appInfo.packageName, false, userId);
                            checkTime(startTime, "getContentProviderImpl: after set stopped state");
                        } catch (RemoteException e) {
                        } catch (IllegalArgumentException e) {
                            Slog.w(TAG, "Failed trying to unstop package "
                                    + cpr.appInfo.packageName + ": " + e);
                        }
                        // Use existing process if already started
                        checkTime(startTime, "getContentProviderImpl: looking for process record");
                        // 获取ContentProvider宿主进程
                        ProcessRecord proc = getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false);
                        if (proc != null && proc.thread != null && !proc.killed) {
                            // ContentProvider宿主进程已经运行
                            if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
                                    "Installing in existing process " + proc);
                            if (!proc.pubProviders.containsKey(cpi.name)) {
                                // ContentProvider没有发布
                                checkTime(startTime, "getContentProviderImpl: scheduling install");
                                // ContentProviderRecord放入pubProviders
                                proc.pubProviders.put(cpi.name, cpr);
                                try {
                                    // 通过Binder IPC请求宿主进程安装发布ContentProvider
                                    proc.thread.scheduleInstallProvider(cpi);
                                } catch (RemoteException e) {
                                }
                            }
                        } else {
                            // ContentProvider宿主进程还没有运行
                            checkTime(startTime, "getContentProviderImpl: before start process");
                            // 启动宿主进程
                            proc = startProcessLocked(cpi.processName,
                                    cpr.appInfo, false, 0, "content provider",
                                    new ComponentName(cpi.applicationInfo.packageName,
                                            cpi.name), false, false, false);
                            checkTime(startTime, "getContentProviderImpl: after start process");
                            if (proc == null) {
                                Slog.w(TAG, "Unable to launch app "
                                        + cpi.applicationInfo.packageName + "/"
                                        + cpi.applicationInfo.uid + " for provider "
                                        + name + ": process is bad");
                                return null;
                            }
                        }
                        // 记录正在启动ContentProvider的宿主进程
                        cpr.launchingApp = proc;
                        // mLaunchingProviders记录正在启动的ContentProvider,ContentProvider发布后从该列表中删除相应ContentProviderRecord
                        mLaunchingProviders.add(cpr);
                    } finally {
                        Binder.restoreCallingIdentity(origId);
                    }
                }
                checkTime(startTime, "getContentProviderImpl: updating data structures");
                // Make sure the provider is published (the same provider class
                // may be published under multiple names).
                // ContentProviderRecord添加到mProviderMap
                if (firstClass) {
                    mProviderMap.putProviderByClass(comp, cpr);
                }
                // 不同的name可能映射到向相同的cpr
                mProviderMap.putProviderByName(name, cpr);
                // 增加引用计数,返回ContentProviderConnection
                conn = incProviderCountLocked(r, cpr, token, stable);
                if (conn != null) {
                    conn.waiting = true;
                }
            }
            checkTime(startTime, "getContentProviderImpl: done!");
        }
        // Wait for the provider to be published...
        synchronized (cpr) {
            while (cpr.provider == null) {
                ......
                try {
                    if (DEBUG_MU) Slog.v(TAG_MU,
                            "Waiting to start provider " + cpr
                            + " launchingApp=" + cpr.launchingApp);
                    if (conn != null) {
                        conn.waiting = true;
                    }
                    // 等待ContentProvider宿主进程发布
                    cpr.wait();
                } catch (InterruptedException ex) {
                } finally {
                    if (conn != null) {
                        conn.waiting = false;
                    }
                }
            }
        }
        return cpr != null ? cpr.newHolder(conn) : null;
    }
    
    public void scheduleInstallProvider(ProviderInfo provider) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        provider.writeToParcel(data, 0);
        // FLAG_ONEWAY表示收到Binder驱动发送的Binder传输完成协议后立即返回
        mRemote.transact(SCHEDULE_INSTALL_PROVIDER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
        data.recycle();
    }
    

    假定ContentProvider宿主进程已经启动,ContentProvider尚未安装发布。下面看ContentProvider宿主进程安装发布ContentProvider的过程,从scheduleInstallProvider()开始分析。

    public void scheduleInstallProvider(ProviderInfo provider) {
        // 请求UI线程安装ContentProvider
        sendMessage(H.INSTALL_PROVIDER, provider);
    }
    
    public void handleInstallProvider(ProviderInfo info) {
        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
        try {
            // mInitialApplication为应用Application对象
            installContentProviders(mInitialApplication, Lists.newArrayList(info));
        } finally {
            StrictMode.setThreadPolicy(oldPolicy);
        }
    }
    
    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<IActivityManager.ContentProviderHolder> results =
            new ArrayList<IActivityManager.ContentProviderHolder>();
        for (ProviderInfo cpi : providers) {
            ......
            // 安装ContentProvider
            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }
        try {
            // 发布ContentProvider
            ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    

    下面看安装ContentProvider的过程。由于ContentProvider宿主进程及客户端进程都需要调用installProvider(),这里只关注ContentProvider宿主进程的执行过程。

    private IActivityManager.ContentProviderHolder installProvider(Context context,
            IActivityManager.ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
        ContentProvider localProvider = null;
        IContentProvider provider;
        if (holder == null || holder.provider == null) {
            // 需要实例化ContentProvider
            ......
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
            if (context.getPackageName().equals(ai.packageName)) {
                c = context;
            } else if (mInitialApplication != null &&
                    mInitialApplication.getPackageName().equals(ai.packageName)) {
                c = mInitialApplication;
            } else {
                try {
                    c = context.createPackageContext(ai.packageName,
                            Context.CONTEXT_INCLUDE_CODE);
                } catch (PackageManager.NameNotFoundException e) {
                    // Ignore
                }
            }
            ......
            try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                // 创建ContentProvider
                localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();
                // provider为Transport对象
                provider = localProvider.getIContentProvider();
                if (provider == null) {
                    Slog.e(TAG, "Failed to instantiate class " +
                          info.name + " from sourceDir " +
                          info.applicationInfo.sourceDir);
                    return null;
                }
                if (DEBUG_PROVIDER) Slog.v(
                    TAG, "Instantiating local provider " + info.name);
                // XXX Need to create the correct context for this provider.
                // 设置Provider信息(权限等),调用onCreate方法
                localProvider.attachInfo(c, info);
            } catch (java.lang.Exception e) {
                if (!mInstrumentation.onException(null, e)) {
                    throw new RuntimeException(
                            "Unable to get provider " + info.name
                            + ": " + e.toString(), e);
                }
                return null;
            }
        } else {
            ......
        }
        
        IActivityManager.ContentProviderHolder retHolder;
        synchronized (mProviderMap) {
            if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
                    + " / " + info.name);
            // jBinder是Binder对象
            IBinder jBinder = provider.asBinder();
            if (localProvider != null) {
                // 根据组件名查询ProviderClientRecord
                ComponentName cname = new ComponentName(info.packageName, info.name);
                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                if (pr != null) {
                    if (DEBUG_PROVIDER) {
                        Slog.v(TAG, "installProvider: lost the race, "
                                + "using existing local provider");
                    }
                    provider = pr.mProvider;
                } else {
                    holder = new IActivityManager.ContentProviderHolder(info);
                    // provider为Transport对象
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    // 为ContentProvider创建ProviderClientRecord
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    // 添加到mLocalProviders及mLocalProvidersByName
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {
               ......
            }
        }
        return retHolder;
    }
    

    下面看ContentProvider的发布过程。

    public void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeTypedList(providers);
        // 非FLAG_ONEWAY, 等待回复
        mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
    
    public final void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) {
        if (providers == null) {
            return;
        }
        enforceNotIsolatedCaller("publishContentProviders");
        synchronized (this) {
            // caller通常为ApplicationThreadProxy对象
            // 查找ContentProvider宿主进程
            final ProcessRecord r = getRecordForAppLocked(caller);
            if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
            if (r == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                      + " (pid=" + Binder.getCallingPid()
                      + ") when publishing content providers");
            }
            final long origId = Binder.clearCallingIdentity();
            final int N = providers.size();
            for (int i = 0; i < N; i++) {
                ContentProviderHolder src = providers.get(i);
                if (src == null || src.info == null || src.provider == null) {
                    continue;
                }
                // 从pubProviders中查到ContentProviderRecord
                ContentProviderRecord dst = r.pubProviders.get(src.info.name);
                if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
                if (dst != null) {
                    ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                    // ContentProviderRecord添加到mProviderMap
                    mProviderMap.putProviderByClass(comp, dst);
                    String names[] = dst.info.authority.split(";");
                    for (int j = 0; j < names.length; j++) {
                        // 多个authority对应同一个ContentProviderRecord
                        mProviderMap.putProviderByName(names[j], dst);
                    }
                    // ContentProvider发布,从mLaunchingProviders移除
                    int launchingCount = mLaunchingProviders.size();
                    int j;
                    boolean wasInLaunchingProviders = false;
                    for (j = 0; j < launchingCount; j++) {
                        if (mLaunchingProviders.get(j) == dst) {
                            mLaunchingProviders.remove(j);
                            wasInLaunchingProviders = true;
                            j--;
                            launchingCount--;
                        }
                    }
                    if (wasInLaunchingProviders) {
                        // 移除ContentProvider超时消息
                        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                    }
                    synchronized (dst) {
                        // provider通常为ContentProviderProxy对象
                        // 唤醒ContentProvider发布的等待着
                        dst.provider = src.provider;
                        dst.proc = r;
                        dst.notifyAll();
                    }
                    ......
                }
            }
            Binder.restoreCallingIdentity(origId);
        }
    }
    

    ContentProvider的发布等待者(通常是system_server的Binder线程)被唤醒后,将发送ContentProviderHolder对象给ContentProvider客户端。

        private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
                String name, IBinder token, boolean stable, int userId) {
            ......
            synchronized (cpr) {
                while (cpr.provider == null) {
                    ......
                    try {
                        if (DEBUG_MU) Slog.v(TAG_MU,
                                "Waiting to start provider " + cpr
                                + " launchingApp=" + cpr.launchingApp);
                        if (conn != null) {
                            conn.waiting = true;
                        }
                        // 从此被唤醒,此时cpr.provider不为null
                        cpr.wait();
                    } catch (InterruptedException ex) {
                    } finally {
                        if (conn != null) {
                            conn.waiting = false;
                        }
                    }
                }
            }
            // 返回ContentProviderHolder对象
            return cpr != null ? cpr.newHolder(conn) : null;
        }        
    

    下面看ContentProvider客户端收到回复后安装ContentProvider的过程。

        public final IContentProvider acquireProvider(
                Context c, String auth, int userId, boolean stable) {
            ......
    
            // There is a possible race here.  Another thread may try to acquire
            // the same provider at the same time.  When this happens, we want to ensure
            // that the first one wins.
            // Note that we cannot hold the lock while acquiring and installing the
            // provider since it might take a long time to run and it could also potentially
            // be re-entrant in the case where the provider is in the same process.
            IActivityManager.ContentProviderHolder holder = null;
            try {
                // 返回ContentProviderHolder
                holder = ActivityManagerNative.getDefault().getContentProvider(
                        getApplicationThread(), auth, userId, stable);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            if (holder == null) {
                Slog.e(TAG, "Failed to find provider info for " + auth);
                return null;
            }
    
            // Install provider will increment the reference count for us, and break
            // any ties in the race.
            // 安装provider,系统进程(uid == 0 || uid == SYSTEM_UID)中,holder.noReleaseNeeded为true
            holder = installProvider(c, holder, holder.info,
                    true /*noisy*/, holder.noReleaseNeeded, stable);
            // 非可运行ContentProvider客户端进程返回ContentProviderProxy对象
            return holder.provider;
        }
    

    需要注意,如果ContentProvider客户端进程可运行ContentProvider,那么holder.provider为null,下面以普通客户端进程为例说明安装过程。

    private IActivityManager.ContentProviderHolder installProvider(Context context,
            IActivityManager.ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
        ContentProvider localProvider = null;
        IContentProvider provider;
        if (holder == null || holder.provider == null) {
            // 可运行ContentProvider客户端进程
            ......
        } else {
            // provider为ContentProviderProxy对象
            provider = holder.provider;
            if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                    + info.name);
        }
        IActivityManager.ContentProviderHolder retHolder;
        synchronized (mProviderMap) {
            if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
                    + " / " + info.name);
            // jBinder为BinderProxy对象
            IBinder jBinder = provider.asBinder();
            if (localProvider != null) {
                ......
            } else {
                // 
                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                if (prc != null) {
                    if (DEBUG_PROVIDER) {
                        Slog.v(TAG, "installProvider: lost the race, updating ref count");
                    }
                    // We need to transfer our new reference to the existing
                    // ref count, releasing the old one...  but only if
                    // release is needed (that is, it is not running in the
                    // system process).
                    if (!noReleaseNeeded) {
                        incProviderRefLocked(prc, stable);
                        try {
                            ActivityManagerNative.getDefault().removeContentProvider(
                                    holder.connection, stable);
                        } catch (RemoteException e) {
                            //do nothing content provider object is dead any way
                        }
                    }
                } else {
                    // 创建ProviderClientRecord添加到mProviderMap
                    ProviderClientRecord client = installProviderAuthoritiesLocked(
                            provider, localProvider, holder);
                    if (noReleaseNeeded) {
                        prc = new ProviderRefCount(holder, client, 1000, 1000);
                    } else {
                        // 创建ProviderRefCount
                        prc = stable
                                ? new ProviderRefCount(holder, client, 1, 0)
                                : new ProviderRefCount(holder, client, 0, 1);
                    }
                    // ProviderRefCount添加到mProviderRefCountMap
                    mProviderRefCountMap.put(jBinder, prc);
                }
                retHolder = prc.holder;
            }
        }
        return retHolder;
    }
    

    现在ContentProvider客户端进程已经得到了ContentProviderProxy对象,下面看使用ContentProviderProxy对象访问ContentProvider的过程。

    使用ContentProviderProxy对象访问ContentProvider的过程

    使用ContentProviderProxy对象访问ContentProvider的过程中涉及的类比较繁杂,首先看下类图:

    • ContentObserver
      • 观察者模式,接收Content改变的回调
    • ContentObserver.Transport
      • 继承自IContentObserver.Stub, 接收Content的改变
    • SelfContentObserver
    • BulkCursorToCursorAdapter
      • 适配器模式,转换IBulkCursor接口到Cursor
    • BulkCursorDescriptor
      • 记录CursorToBulkCursorAdapter中Cursor的属性,用于在客户端初始化BulkCursorToCursorAdapter
    • BulkCursorNative
      • 用于实现进程间通信
    • CursorToBulkCursorAdapter
      • 适配器模式,转换Cursor接口到IBulkCursor,继承自BulkCursorNative,支持进程间通信
    • CursorWindow
      • 包含数据库多行内容的buffer,用于进程间(ContentProvider客户端与ContentProvider宿主)共享数据

    下面从ContentResolverquery()开始分析。

    public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
            @Nullable String[] projection, @Nullable String selection,
            @Nullable String[] selectionArgs, @Nullable String sortOrder,
            @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        // 这里unstableProvider为ContentProviderProxy对象
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        ......
        try {
            long startTime = SystemClock.uptimeMillis();
            ......
            try {
                // 通过Binder IPC向ContentProvider查询数据库信息
                // qCursor为BulkCursorToCursorAdapter对象
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, 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
                // 处理ContentProvider宿主进程死亡的情况
                unstableProviderDied(unstableProvider);
                stableProvider = acquireProvider(uri);
                if (stableProvider == null) {
                    return null;
                }
                qCursor = stableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            }
            ......
            // 增加stableProvider引用计数
            final IContentProvider provider = (stableProvider != null) ? stableProvider
                    : acquireProvider(uri);
            // 创建CursorWrapperInner对象
            final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
            stableProvider = null;
            qCursor = null;
            // 返回CursorWrapperInner
            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) {
                // 减少unstableProvider引用计数
                releaseUnstableProvider(unstableProvider);
            }
            if (stableProvider != null) {
                releaseProvider(stableProvider);
            }
        }
    }
    

    下面看ContentProviderProxyquery()的实现

    public Cursor query(String callingPkg, 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);
            data.writeString(callingPkg);
            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);
            // adaptor.getObserver()返回ContentObserver.Transport对象
            data.writeStrongBinder(adaptor.getObserver().asBinder());
            data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
            // Binder IPC,需要等待回复
            mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
            DatabaseUtils.readExceptionFromParcel(reply);
            if (reply.readInt() != 0) {
                // 从Parcel中创建BulkCursorDescriptor对象
                BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
                // 调用BulkCursorToCursorAdaptor的初始化方法
                adaptor.initialize(d);
            } else {
                adaptor.close();
                adaptor = null;
            }
            // 返回BulkCursorToCursorAdaptor
            return adaptor;
        }
        ......
    }
    

    下面看ContentProvider宿主进程处理QUERY_TRANSACTION请求。

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        try {
            switch (code) {
                case QUERY_TRANSACTION:
                {
                    data.enforceInterface(IContentProvider.descriptor);
                    String callingPkg = data.readString();
                    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();
                    // 通常observer为IContentObserver.Stub.Proxy对象
                    IContentObserver observer = IContentObserver.Stub.asInterface(
                            data.readStrongBinder());
                    ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                            data.readStrongBinder());
                    // 调用ContentProvider.Transport的query
                    Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
                            sortOrder, cancellationSignal);
                    if (cursor != null) {
                        CursorToBulkCursorAdaptor adaptor = null;
                        try {
                            // 创建CursorToBulkCursorAdaptor
                            adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
                                    getProviderName());
                            cursor = null;
                            // 工厂方法,创建BulkCursorDescriptor记录adaptor中Cursor的属性
                            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;
                }
                ......
            }
            ......
        }
        ......
    }
    
    public Cursor query(String callingPkg, Uri uri, String[] projection,
            String selection, String[] selectionArgs, String sortOrder,
            ICancellationSignal cancellationSignal) {
        validateIncomingUri(uri);
        uri = getUriWithoutUserId(uri);
        // 检查客户端是否有权限读取Content
        if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
            // 客户端没有权限,返回空的MatrixCursor对象
            // 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 = ContentProvider.this.query(uri, projection, selection,
                    selectionArgs, sortOrder, CancellationSignal.fromTransport(
                            cancellationSignal));
            if (cursor == null) {
                return null;
            }
            // Return an empty cursor for all columns.
            return new MatrixCursor(cursor.getColumnNames(), 0);
        }
        final String original = setCallingPackage(callingPkg);
        try {
            // 调用ContentProvider的query,这里假定返回MatrixCursor对象
            return ContentProvider.this.query(
                    uri, projection, selection, selectionArgs, sortOrder,
                    CancellationSignal.fromTransport(cancellationSignal));
        } finally {
            setCallingPackage(original);
        }
    }
    

    ContentProvider客户端通过ContentProviderProxyquery()方法获取了ContentProvider的一些信息(Count/ColumnNames等),但是没有得到真正的数据内容,下面分析获取ContentProvider真正数据的过程。

    ContentProvider客户端使用Cursor获取ContentProvider数据的过程

    从前面的分析可知,调用getContentResolver().query()返回CursorWrapperInner类型的对象。

    • CursorWrapperInner
      • 使用完后,要关闭
      • GC回收CursorWrapperInner时,会关闭Cursor
    • CursorWrapper
      • Cursor的封装,用于实现仅需要重写Cursor部分接口的子类
    • CrossProcessCursorWrapper
      • 可用于适配原始的Cursor到CrossProcessCursor,适配器模式
        获取CursorWrapperInner对象后,通过MoveToFirst()建立ContentProvider共享数据,然后使用getXxx()访问共享数据。

    MoveToFirst处理过程

    public boolean moveToFirst() {
        // mCursor为BulkCursorToCursorAdapter对象
        return mCursor.moveToFirst();
    }
    
    // BulkCursorToCursorAdapter继承自AbstractCursor
    public final boolean moveToFirst() {
        // 调用moveToPosition,设置位置为0
        return moveToPosition(0);
    }
    
    public final boolean moveToPosition(int position) {
        // Make sure position isn't past the end of the cursor
        // position可以理解为数据库Row id
        final int count = getCount();
        if (position >= count) {
            mPos = count;
            return false;
        }
        // Make sure position isn't before the beginning of the cursor
        if (position < 0) {
            mPos = -1;
            return false;
        }
        // Check for no-op moves, and skip the rest of the work for them
        // 当前位置等于目标位置,直接返回
        if (position == mPos) {
            return true;
        }
        // 当前位置移动得到目标位置
        boolean result = onMove(mPos, position);
        if (result == false) {
            mPos = -1;
        } else {
            // 修改当前位置
            mPos = position;
        }
        return result;
    }
    

    BulkCursorToCursorAdapter重写了onMove(),下面分析它的实现。

    public boolean onMove(int oldPosition, int newPosition) {
        // 如果Cursor已经关闭抛出异常
        throwIfCursorIsClosed();
        try {
            // Make sure we have the proper window
            // 这里mWindow为null
            if (mWindow == null
                    || newPosition < mWindow.getStartPosition()
                    || newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
                // mBulkCursor为BulkCursorProxy对象      
                // 获取、设置CursorWindow
                setWindow(mBulkCursor.getWindow(newPosition));
            } else if (mWantsAllOnMoveCalls) {
                // mWantsAllOnMoveCalls默认为false,如果为true,onMove为跨进程调用
                mBulkCursor.onMove(newPosition);
            }
        } catch (RemoteException ex) {
            // We tried to get a window and failed
            Log.e(TAG, "Unable to get window because the remote process is dead");
            return false;
        }
        // Couldn't obtain a window, something is wrong
        if (mWindow == null) {
            return false;
        }
        return true;
    }
    
    public CursorWindow getWindow(int position) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(IBulkCursor.descriptor);
            // 传递目标位置
            data.writeInt(position);
            // 同步Binder通信,获取CursorWindow
            mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
            DatabaseUtils.readExceptionFromParcel(reply);
            CursorWindow window = null;
            if (reply.readInt() == 1) {
                // 从Parcel中重建CursorWindow
                window = CursorWindow.newFromParcel(reply);
            }
            return window;
        } finally {
            data.recycle();
            reply.recycle();
        }
    }
    

    下面看ContentProvider宿主进程(服务端)创建CursorWindow的过程。

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        try {
            switch (code) {
                case GET_CURSOR_WINDOW_TRANSACTION: {
                    data.enforceInterface(IBulkCursor.descriptor);
                    // 目标位置
                    int startPos = data.readInt();
                    // 调用CursorToBulkCursorAdaptor的getWindow
                    CursorWindow window = getWindow(startPos);
                    reply.writeNoException();
                    if (window == null) {
                        reply.writeInt(0);
                    } else {
                        // CursorWindow创建成功
                        reply.writeInt(1);
                        // 写入Parcel,主要涉及Binder跨进程传递文件描述符
                        window.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    return true;
                }
                ......
            }
            ......
        }
        ......
    }
    
    public CursorWindow getWindow(int position) {
        synchronized (mLock) {
            throwIfCursorIsClosed();
            // mCursor为MatrixCursor对象,修改Cursor的当前位置
            if (!mCursor.moveToPosition(position)) {
                closeFilledWindowLocked();
                return null;
            }
            // getWindow返回null
            CursorWindow window = mCursor.getWindow();
            if (window != null) {
                closeFilledWindowLocked();
            } else {
                // mFilledWindow为null
                window = mFilledWindow;
                if (window == null) {
                    // 创建CursorWindow
                    mFilledWindow = new CursorWindow(mProviderName);
                    window = mFilledWindow;
                } else if (position < window.getStartPosition()
                        || position >= window.getStartPosition() + window.getNumRows()) {
                    window.clear();
                }
                // Cursor中的数据拷贝至CursorWindow(匿名共享内存)
                mCursor.fillWindow(position, window);
            }
            if (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.
                window.acquireReference();
            }
            return window;
        }
    }
    

    下面首先看CursorWindow的创建过程,然后分析数据拷贝至CursorWindow的过程。

    public CursorWindow(String name) {
        mStartPos = 0;
        mName = name != null && name.length() != 0 ? name : "<unnamed>";
        if (sCursorWindowSize < 0) {
            /** The cursor window size. resource xml file specifies the value in kB.
             * convert it to bytes here by multiplying with 1024.
             */
            // CursorWindow大小默认2MB
            sCursorWindowSize = Resources.getSystem().getInteger(
                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
        }
        // 创建Native层CursorWindow及匿名共享内存
        mWindowPtr = nativeCreate(mName, sCursorWindowSize);
        if (mWindowPtr == 0) {
            throw new CursorWindowAllocationException("Cursor window allocation of " +
                    (sCursorWindowSize / 1024) + " kb failed. " + printStats());
        }
        // CloseGuard用于确保在CursorWindow被回收之前释放匿名共享内存
        mCloseGuard.open("close");
        // mWindowPtr添加到sWindowToPidMap中
        recordNewWindow(Binder.getCallingPid(), mWindowPtr);
    }
    

    下面看nativeCreate()的实现

    static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
        String8 name;
        const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
        name.setTo(nameStr);
        env->ReleaseStringUTFChars(nameObj, nameStr);
    
        CursorWindow* window;
        // 创建匿名共享内存及Native层的CursorWindow
        status_t status = CursorWindow::create(name, cursorWindowSize, &window);
        if (status || !window) {
            ALOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
                    name.string(), cursorWindowSize, status);
            return 0;
        }
    
        LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
        return reinterpret_cast<jlong>(window);
    }
    
    status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
        // 匿名共享内存区域以CursorWindow:开头,see内存映射信息
        String8 ashmemName("CursorWindow: ");
        ashmemName.append(name);
    
        status_t result;
        // 创建匿名共享内存区域
        int ashmemFd = ashmem_create_region(ashmemName.string(), size);
        if (ashmemFd < 0) {
            result = -errno;
        } else {
            result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
            if (result >= 0) {
                // 映射虚拟内存区域用于读写匿名共享内存
                void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
                if (data == MAP_FAILED) {
                    result = -errno;
                } else {
                    result = ashmem_set_prot_region(ashmemFd, PROT_READ);
                    if (result >= 0) {
                        // 创建CursorWindow
                        CursorWindow* window = new CursorWindow(name, ashmemFd,
                                data, size, false /*readOnly*/);
                        // 初始化CursorWindow
                        result = window->clear();
                        if (!result) {
                            LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
                                    "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                    window->mHeader->freeOffset,
                                    window->mHeader->numRows,
                                    window->mHeader->numColumns,
                                    window->mSize, window->mData);
                            // 返回CursorWindow地址
                            *outCursorWindow = window;
                            return OK;
                        }
                        delete window;
                    }
                }
                ::munmap(data, size);
            }
            ::close(ashmemFd);
        }
        *outCursorWindow = NULL;
        return result;
    }
    

    至此,CursorWindow的创建过程分析完了,下面看Cursor中的数据拷贝至CursorWindow的过程。

    public void fillWindow(int position, CursorWindow window) {
        DatabaseUtils.cursorFillWindow(this, position, window);
    }
    
    public static void cursorFillWindow(final Cursor cursor,
            int position, final CursorWindow window) {
        if (position < 0 || position >= cursor.getCount()) {
            return;
        }
        // 保存原来的位置
        final int oldPos = cursor.getPosition();
        final int numColumns = cursor.getColumnCount();
        // 初始化CursorWindow
        window.clear();
        // 设置CursorWindow的起始位置为position
        window.setStartPosition(position);
        // 设置CursorWindow的列数
        window.setNumColumns(numColumns);
        // cursor移动到目标位置
        if (cursor.moveToPosition(position)) {
            rowloop: do {
                // CursorWindow分配一行空间
                if (!window.allocRow()) {
                    break;
                }
                // 遍历列,将当前行的每个列数据拷贝至CursorWindow
                for (int i = 0; i < numColumns; i++) {
                    // 列类型
                    final int type = cursor.getType(i);
                    final boolean success;
                    switch (type) {
                        case Cursor.FIELD_TYPE_NULL:
                            success = window.putNull(position, i);
                            break;
                        case Cursor.FIELD_TYPE_INTEGER:
                            success = window.putLong(cursor.getLong(i), position, i);
                            break;
                        case Cursor.FIELD_TYPE_FLOAT:
                            success = window.putDouble(cursor.getDouble(i), position, i);
                            break;
                        case Cursor.FIELD_TYPE_BLOB: {
                            final byte[] value = cursor.getBlob(i);
                            success = value != null ? window.putBlob(value, position, i)
                                    : window.putNull(position, i);
                            break;
                        }
                        default: // assume value is convertible to String
                        case Cursor.FIELD_TYPE_STRING: {
                            final String value = cursor.getString(i);
                            success = value != null ? window.putString(value, position, i)
                                    : window.putNull(position, i);
                            break;
                        }
                    }
                    if (!success) {
                        window.freeLastRow();
                        break rowloop;
                    }
                }
                position += 1;
                // cursor移动到下一行
            } while (cursor.moveToNext());
        }
        // cursor恢复原来的位置
        cursor.moveToPosition(oldPos);
    }
    

    下面只分析FIELD_TYPE_STRING类型数据的拷贝过程,也就是CursorWindowputString的实现。在分析之前先了解Native层CursorWindow的内存布局。

    • CursorWindow的Header
      • freeOffset: CursorWindow空闲区域的偏移
      • firstChunkOffset: 第一个RowSlot的偏移
      • numRows: 行数
      • numColumns: 列数
    • RowSlotChunk
      • slots: 预分配的RowSlot,默认100个
      • nextChunkOffset: 如果预分配的RowSlot不够用,表示下一个RowSlotChunk在CursorWindow中的偏移
    • RowSlot
      • offset: 记录一行数据在CursorWindow中的偏移
    • FieldSlot(记录一个列数据)
      • type: 列数据类型
      • 列类型为double/long
        • data.d/data.l: 值
      • 列类型为String/Blob
        • data.buffer.offset: String/Blob内容在CursorWindow中的偏移
        • data.buffer.size: String/Blob内容大小
      • 列类型为Null
        • data.buffer.offset: 0
        • data.buffer.size: 0
          下面看putString()的实现。
    public boolean putString(String value, int row, int column) {
        acquireReference();
        try {
            return nativePutString(mWindowPtr, value, row - mStartPos, column);
        } finally {
            releaseReference();
        }
    }
    
    static jboolean nativePutString(JNIEnv* env, jclass clazz, jlong windowPtr,
            jstring valueObj, jint row, jint column) {
        // Native层的CursorWindow
        CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
    
        size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
        const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
        if (!valueStr) {
            LOG_WINDOW("value can't be transferred to UTFChars");
            return false;
        }
        // 调用CursorWindow的putString,这里sizeIncludingNull包含字符串结束符
        status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
        env->ReleaseStringUTFChars(valueObj, valueStr);
        ......
        return true;
    }
    
    status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
            size_t sizeIncludingNull) {
        return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
    }
    
    status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
            const void* value, size_t size, int32_t type) {
        if (mReadOnly) {
            return INVALID_OPERATION;
        }
        // 查找所属FieldSlot
        FieldSlot* fieldSlot = getFieldSlot(row, column);
        if (!fieldSlot) {
            return BAD_VALUE;
        }
        // 对于Blob(字节数组)或String, 单独分配存储空间
        uint32_t offset = alloc(size);
        if (!offset) {
            return NO_MEMORY;
        }
        // String内容拷贝至分配的空间中
        memcpy(offsetToPtr(offset), value, size);
        // 记录String数据信息
        fieldSlot->type = type;
        fieldSlot->data.buffer.offset = offset;
        fieldSlot->data.buffer.size = size;
        return OK;
    }
    

    至此,ContentProvider宿主进程的getWindow()分析完成,下面看ContentProvider客户端收到回复后建立匿名共享内存的过程。

    public CursorWindow getWindow(int position) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            ......
            if (reply.readInt() == 1) {
                // 从Parcel中重建CursorWindow
                window = CursorWindow.newFromParcel(reply);
            }
            return window;
        } finally {
            data.recycle();
            reply.recycle();
        }
    }
    
    public static final Parcelable.Creator<CursorWindow> CREATOR
            = new Parcelable.Creator<CursorWindow>() {
        public CursorWindow createFromParcel(Parcel source) {
            return new CursorWindow(source);
        }
        ......
    };
    public static CursorWindow newFromParcel(Parcel p) {
        return CREATOR.createFromParcel(p);
    }
    
    private CursorWindow(Parcel source) {
        // 起始位置
        mStartPos = source.readInt();
        // 从Parcel建立匿名共享内存
        mWindowPtr = nativeCreateFromParcel(source);
        if (mWindowPtr == 0) {
            throw new CursorWindowAllocationException("Cursor window could not be "
                    + "created from binder.");
        }
        mName = nativeGetName(mWindowPtr);
        mCloseGuard.open("close");
    }
    

    下面看nativeCreateFromParcel()的实现

    static jlong nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
        Parcel* parcel = parcelForJavaObject(env, parcelObj);
    
        CursorWindow* window;
        status_t status = CursorWindow::createFromParcel(parcel, &window);
        ......
        return reinterpret_cast<jlong>(window);
    }
    
    status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
        String8 name = parcel->readString8();
    
        status_t result;
        // 匿名共享内存文件描述符
        int ashmemFd = parcel->readFileDescriptor();
        if (ashmemFd == int(BAD_TYPE)) {
            result = BAD_TYPE;
        } else {
            // 获取匿名共享内存区域大小
            ssize_t size = ashmem_get_size_region(ashmemFd);
            if (size < 0) {
                result = UNKNOWN_ERROR;
            } else {
                // 创建文件描述符ashmemFd的拷贝
                int dupAshmemFd = ::dup(ashmemFd);
                if (dupAshmemFd < 0) {
                    result = -errno;
                } else {
                    // 映射虚拟地址空间用以读取匿名共享内存
                    void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
                    if (data == MAP_FAILED) {
                        result = -errno;
                    } else {
                        // 创建CursorWindow
                        CursorWindow* window = new CursorWindow(name, dupAshmemFd,
                                data, size, true /*readOnly*/);
                        LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
                                "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                window->mHeader->freeOffset,
                                window->mHeader->numRows,
                                window->mHeader->numColumns,
                                window->mSize, window->mData);
                        *outCursorWindow = window;
                        return OK;
                    }
                    ::close(dupAshmemFd);
                }
            }
        }
        *outCursorWindow = NULL;
        return result;
    }
    

    这样,ContentProvider客户端与ContentProvider宿主进程之间就建立起了匿名共享内存,此后ContentProvider客户端只需访问匿名共享内存就能获取Content数据。

    getXxx(以getString为例分析)处理过程

    下面从CursorWrapperInnergetString()开始分析

    public String getString(int columnIndex) {
        // mCursor为BulkCursorToCursorAdapter类型的对象
        return mCursor.getString(columnIndex);
    }
    
    public String getString(int columnIndex) {
        // 检查当前的位置(Row)是否合法
        checkPosition();
        // 调用CursorWindow的getString
        return mWindow.getString(mPos, columnIndex);
    }
    
    public String getString(int row, int column) {
        acquireReference();
        try {
            // 从CursorWindow(匿名共享内存)中读取String
            return nativeGetString(mWindowPtr, row - mStartPos, column);
        } finally {
            releaseReference();
        }
    }
    

    下面看nativeGetString()的实现

    static jstring nativeGetString(JNIEnv* env, jclass clazz, jlong windowPtr,
            jint row, jint column) {
        // 获取Native层的CursorWindow
        CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
        LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
        // 根据行、列号找到对应的FieldSlot
        CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
        if (!fieldSlot) {
            throwExceptionWithRowCol(env, row, column);
            return NULL;
        }
    
        // 读取列数据类型
        int32_t type = window->getFieldSlotType(fieldSlot);
        if (type == CursorWindow::FIELD_TYPE_STRING) {
            size_t sizeIncludingNull;
            // 字符串内容地址
            const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
            if (sizeIncludingNull <= 1) {
                return gEmptyString;
            }
            // Convert to UTF-16 here instead of calling NewStringUTF.  NewStringUTF
            // doesn't like UTF-8 strings with high codepoints.  It actually expects
            // Modified UTF-8 with encoded surrogate pairs.
            String16 utf16(value, sizeIncludingNull - 1);
            // 返回字符串
            return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
        } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
            int64_t value = window->getFieldSlotValueLong(fieldSlot);
            char buf[32];
            snprintf(buf, sizeof(buf), "%" PRId64, value);
            return env->NewStringUTF(buf);
        } else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
            double value = window->getFieldSlotValueDouble(fieldSlot);
            char buf[32];
            snprintf(buf, sizeof(buf), "%g", value);
            return env->NewStringUTF(buf);
        } else if (type == CursorWindow::FIELD_TYPE_NULL) {
            return NULL;
        } else if (type == CursorWindow::FIELD_TYPE_BLOB) {
            throw_sqlite3_exception(env, "Unable to convert BLOB to string");
            return NULL;
        } else {
            throwUnknownTypeException(env, type);
            return NULL;
        }
    }
    

    小结

    参考

    https://developer.android.com/guide/topics/providers/content-provider-basics?hl=zh-cn

    相关文章

      网友评论

        本文标题:Android ContentProvider

        本文链接:https://www.haomeiwen.com/subject/rgcjbftx.html