Android ContentProvider

本文基于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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容