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
    • 應(yīng)用使用該類訪問ContentProvider
  • ContentProviderProxy
    • ContentProvider代理對象
  • ContentProviderNative
    • ContentProvider本地對象
  • Transport
    • 實現(xiàn)了ContentProviderNative
  • ContentProvider
    • 用于應(yīng)用間共享數(shù)據(jù)

通過ContentResolver獲取ContentProviderProxy對象

下面從ContextImplgetContentResolver()開始分析

public ContentResolver getContentResolver() {
    return mContentResolver;
}

這里mContentResolver是一個ApplicationContentResolver類型的引用,它是在ContextImpl構(gòu)造函數(shù)中創(chuàng)建的,下面看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){
    // 調(diào)用ActivityThread的acquireProvider
    // ContentProvider.getAuthorityWithoutUserId(auth)通常返回auth
    // resolveUserIdFromAuthority(auth)通常返回0
    return mMainThread.acquireProvider(c,
            ContentProvider.getAuthorityWithoutUserId(auth),
            resolveUserIdFromAuthority(auth), false);
}
  • unstableProvider
    • 當(dāng)ContentProvider宿主進程死亡時,系統(tǒng)會通知ContentProvider客戶端進程
  • stableProvider
    • 當(dāng)ContentProvider宿主進程死亡時
      • ContentProviderConnection存在時,系統(tǒng)會殺死非persistent的ContentProvider客戶端進程
      • ContentProviderConnection移除時,系統(tǒng)不會殺ContentProvider客戶端進程
        下面看ActivityThreadacquireProvider()的實現(xiàn)
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.
    // 系統(tǒng)進程(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()的實現(xiàn)

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引用計數(shù)
            incProviderRefLocked(prc, stable);
        }
        return provider;
    }
}
  • ProviderKey
    • 保存authorith以及userId
  • ProviderClientRecord
    • 保存Provider信息(在ContentProvider宿主進程及客戶端均使用)

這里假定acquireExistingProvider()返回null,下面看getContentProvider()的實現(xiàn)

// 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) {
        // 創(chuàng)建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) {
            // 根據(jù)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...
        // 檢查目標(biāo)ContentProvider是否已經(jīng)發(fā)布,cpr不為null也并不意味著ContentProvider已經(jīng)發(fā)布
        cpr = mProviderMap.getProviderByName(name, userId);
        ......
        boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
        if (providerRunning) {
            // ContentProvider已經(jīng)發(fā)布
            cpi = cpr.info;
            String msg;
            ......
            if (r != null && cpr.canRunHere(r)) {
                // ContentProvider能夠運行在調(diào)用者進程,例如:
                // 1) 多進程ContentProvider同時調(diào)用者與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,調(diào)用者自己實例化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引用計數(shù)
            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,調(diào)整
                    // ContentProvider宿主進程及關(guān)聯(lián)進程在LRU鏈表中的位置
                    updateLruProcessLocked(cpr.proc, false, null);
                    checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
                }
            }
            checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
            final int verifiedAdj = cpr.proc.verifiedAdj;
            // 更新ContentProvider宿主進程狀態(tài)及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);
                // 減少引用計數(shù),如果計數(shù)為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");
            // 檢查客戶端是否有權(quán)限訪問ContentProvider
            if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
                    != null) {
                throw new SecurityException(msg);
            }
            checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
            // system準(zhǔn)備好之前不能運行非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");
            // 根據(jù)組件名及userId獲取ContentProviderRecord
            cpr = mProviderMap.getProviderByClass(comp, userId);
            checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
            final boolean firstClass = cpr == null;
            if (firstClass) {
                // 需要創(chuàng)建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);
                    // 創(chuàng)建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能夠運行在調(diào)用者進程,例如:
                // 1) 調(diào)用者是ContentProvider宿主自身
                // 2) 多進程ContentProvider同時調(diào)用者與ContentProvider宿主進程uid相同
                // 這里無需設(shè)置holder.provider為null,ContentProviderRecord創(chuàng)建后成員provider默認(rèn)為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");
                        // 設(shè)置ContentProvider包的狀態(tài)
                        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宿主進程已經(jīng)運行
                        if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
                                "Installing in existing process " + proc);
                        if (!proc.pubProviders.containsKey(cpi.name)) {
                            // ContentProvider沒有發(fā)布
                            checkTime(startTime, "getContentProviderImpl: scheduling install");
                            // ContentProviderRecord放入pubProviders
                            proc.pubProviders.put(cpi.name, cpr);
                            try {
                                // 通過Binder IPC請求宿主進程安裝發(fā)布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發(fā)布后從該列表中刪除相應(yīng)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);
            // 增加引用計數(shù),返回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宿主進程發(fā)布
                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驅(qū)動發(fā)送的Binder傳輸完成協(xié)議后立即返回
    mRemote.transact(SCHEDULE_INSTALL_PROVIDER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
    data.recycle();
}

假定ContentProvider宿主進程已經(jīng)啟動,ContentProvider尚未安裝發(fā)布。下面看ContentProvider宿主進程安裝發(fā)布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為應(yīng)用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 {
        // 發(fā)布ContentProvider
        ActivityManagerNative.getDefault().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

下面看安裝ContentProvider的過程。由于ContentProvider宿主進程及客戶端進程都需要調(diào)用installProvider(),這里只關(guān)注ContentProvider宿主進程的執(zhí)行過程。

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();
            // 創(chuàng)建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.
            // 設(shè)置Provider信息(權(quán)限等),調(diào)用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) {
            // 根據(jù)組件名查詢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創(chuàng)建ProviderClientRecord
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                // 添加到mLocalProviders及mLocalProvidersByName
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
            }
            retHolder = pr.mHolder;
        } else {
           ......
        }
    }
    return retHolder;
}

下面看ContentProvider的發(fā)布過程。

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, 等待回復(fù)
    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對應(yīng)同一個ContentProviderRecord
                    mProviderMap.putProviderByName(names[j], dst);
                }
                // ContentProvider發(fā)布,從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發(fā)布的等待著
                    dst.provider = src.provider;
                    dst.proc = r;
                    dst.notifyAll();
                }
                ......
            }
        }
        Binder.restoreCallingIdentity(origId);
    }
}

ContentProvider的發(fā)布等待者(通常是system_server的Binder線程)被喚醒后,將發(fā)送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客戶端收到回復(fù)后安裝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,系統(tǒng)進程(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 {
                // 創(chuàng)建ProviderClientRecord添加到mProviderMap
                ProviderClientRecord client = installProviderAuthoritiesLocked(
                        provider, localProvider, holder);
                if (noReleaseNeeded) {
                    prc = new ProviderRefCount(holder, client, 1000, 1000);
                } else {
                    // 創(chuàng)建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;
}

現(xiàn)在ContentProvider客戶端進程已經(jīng)得到了ContentProviderProxy對象,下面看使用ContentProviderProxy對象訪問ContentProvider的過程。

使用ContentProviderProxy對象訪問ContentProvider的過程

使用ContentProviderProxy對象訪問ContentProvider的過程中涉及的類比較繁雜,首先看下類圖:

  • ContentObserver
    • 觀察者模式,接收Content改變的回調(diào)
  • ContentObserver.Transport
    • 繼承自IContentObserver.Stub, 接收Content的改變
  • SelfContentObserver
  • BulkCursorToCursorAdapter
    • 適配器模式,轉(zhuǎn)換IBulkCursor接口到Cursor
  • BulkCursorDescriptor
    • 記錄CursorToBulkCursorAdapter中Cursor的屬性,用于在客戶端初始化BulkCursorToCursorAdapter
  • BulkCursorNative
    • 用于實現(xiàn)進程間通信
  • CursorToBulkCursorAdapter
    • 適配器模式,轉(zhuǎn)換Cursor接口到IBulkCursor,繼承自BulkCursorNative,支持進程間通信
  • CursorWindow
    • 包含數(shù)據(jù)庫多行內(nèi)容的buffer,用于進程間(ContentProvider客戶端與ContentProvider宿主)共享數(shù)據(jù)

下面從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查詢數(shù)據(jù)庫信息
            // 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引用計數(shù)
        final IContentProvider provider = (stableProvider != null) ? stableProvider
                : acquireProvider(uri);
        // 創(chuàng)建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引用計數(shù)
            releaseUnstableProvider(unstableProvider);
        }
        if (stableProvider != null) {
            releaseProvider(stableProvider);
        }
    }
}

下面看ContentProviderProxyquery()的實現(xiàn)

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,需要等待回復(fù)
        mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
        DatabaseUtils.readExceptionFromParcel(reply);
        if (reply.readInt() != 0) {
            // 從Parcel中創(chuàng)建BulkCursorDescriptor對象
            BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
            // 調(diào)用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());
                // 調(diào)用ContentProvider.Transport的query
                Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
                        sortOrder, cancellationSignal);
                if (cursor != null) {
                    CursorToBulkCursorAdaptor adaptor = null;
                    try {
                        // 創(chuàng)建CursorToBulkCursorAdaptor
                        adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
                                getProviderName());
                        cursor = null;
                        // 工廠方法,創(chuàng)建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);
    // 檢查客戶端是否有權(quán)限讀取Content
    if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
        // 客戶端沒有權(quán)限,返回空的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 {
        // 調(diào)用ContentProvider的query,這里假定返回MatrixCursor對象
        return ContentProvider.this.query(
                uri, projection, selection, selectionArgs, sortOrder,
                CancellationSignal.fromTransport(cancellationSignal));
    } finally {
        setCallingPackage(original);
    }
}

ContentProvider客戶端通過ContentProviderProxyquery()方法獲取了ContentProvider的一些信息(Count/ColumnNames等),但是沒有得到真正的數(shù)據(jù)內(nèi)容,下面分析獲取ContentProvider真正數(shù)據(jù)的過程。

ContentProvider客戶端使用Cursor獲取ContentProvider數(shù)據(jù)的過程

從前面的分析可知,調(diào)用getContentResolver().query()返回CursorWrapperInner類型的對象。

  • CursorWrapperInner
    • 使用完后,要關(guān)閉
    • GC回收CursorWrapperInner時,會關(guān)閉Cursor
  • CursorWrapper
    • Cursor的封裝,用于實現(xiàn)僅需要重寫Cursor部分接口的子類
  • CrossProcessCursorWrapper
    • 可用于適配原始的Cursor到CrossProcessCursor,適配器模式
      獲取CursorWrapperInner對象后,通過MoveToFirst()建立ContentProvider共享數(shù)據(jù),然后使用getXxx()訪問共享數(shù)據(jù)。

MoveToFirst處理過程

public boolean moveToFirst() {
    // mCursor為BulkCursorToCursorAdapter對象
    return mCursor.moveToFirst();
}

// BulkCursorToCursorAdapter繼承自AbstractCursor
public final boolean moveToFirst() {
    // 調(diào)用moveToPosition,設(shè)置位置為0
    return moveToPosition(0);
}

public final boolean moveToPosition(int position) {
    // Make sure position isn't past the end of the cursor
    // position可以理解為數(shù)據(jù)庫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
    // 當(dāng)前位置等于目標(biāo)位置,直接返回
    if (position == mPos) {
        return true;
    }
    // 當(dāng)前位置移動得到目標(biāo)位置
    boolean result = onMove(mPos, position);
    if (result == false) {
        mPos = -1;
    } else {
        // 修改當(dāng)前位置
        mPos = position;
    }
    return result;
}

BulkCursorToCursorAdapter重寫了onMove(),下面分析它的實現(xiàn)。

public boolean onMove(int oldPosition, int newPosition) {
    // 如果Cursor已經(jīng)關(guān)閉拋出異常
    throwIfCursorIsClosed();
    try {
        // Make sure we have the proper window
        // 這里mWindow為null
        if (mWindow == null
                || newPosition < mWindow.getStartPosition()
                || newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
            // mBulkCursor為BulkCursorProxy對象      
            // 獲取、設(shè)置CursorWindow
            setWindow(mBulkCursor.getWindow(newPosition));
        } else if (mWantsAllOnMoveCalls) {
            // mWantsAllOnMoveCalls默認(rèn)為false,如果為true,onMove為跨進程調(diào)用
            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);
        // 傳遞目標(biāo)位置
        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宿主進程(服務(wù)端)創(chuàng)建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);
                // 目標(biāo)位置
                int startPos = data.readInt();
                // 調(diào)用CursorToBulkCursorAdaptor的getWindow
                CursorWindow window = getWindow(startPos);
                reply.writeNoException();
                if (window == null) {
                    reply.writeInt(0);
                } else {
                    // CursorWindow創(chuàng)建成功
                    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的當(dāng)前位置
        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) {
                // 創(chuàng)建CursorWindow
                mFilledWindow = new CursorWindow(mProviderName);
                window = mFilledWindow;
            } else if (position < window.getStartPosition()
                    || position >= window.getStartPosition() + window.getNumRows()) {
                window.clear();
            }
            // Cursor中的數(shù)據(jù)拷貝至CursorWindow(匿名共享內(nèi)存)
            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的創(chuàng)建過程,然后分析數(shù)據(jù)拷貝至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大小默認(rèn)2MB
        sCursorWindowSize = Resources.getSystem().getInteger(
            com.android.internal.R.integer.config_cursorWindowSize) * 1024;
    }
    // 創(chuàng)建Native層CursorWindow及匿名共享內(nèi)存
    mWindowPtr = nativeCreate(mName, sCursorWindowSize);
    if (mWindowPtr == 0) {
        throw new CursorWindowAllocationException("Cursor window allocation of " +
                (sCursorWindowSize / 1024) + " kb failed. " + printStats());
    }
    // CloseGuard用于確保在CursorWindow被回收之前釋放匿名共享內(nèi)存
    mCloseGuard.open("close");
    // mWindowPtr添加到sWindowToPidMap中
    recordNewWindow(Binder.getCallingPid(), mWindowPtr);
}

下面看nativeCreate()的實現(xiàn)

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;
    // 創(chuàng)建匿名共享內(nèi)存及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) {
    // 匿名共享內(nèi)存區(qū)域以CursorWindow:開頭,see內(nèi)存映射信息
    String8 ashmemName("CursorWindow: ");
    ashmemName.append(name);

    status_t result;
    // 創(chuàng)建匿名共享內(nèi)存區(qū)域
    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) {
            // 映射虛擬內(nèi)存區(qū)域用于讀寫匿名共享內(nèi)存
            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) {
                    // 創(chuàng)建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的創(chuàng)建過程分析完了,下面看Cursor中的數(shù)據(jù)拷貝至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();
    // 設(shè)置CursorWindow的起始位置為position
    window.setStartPosition(position);
    // 設(shè)置CursorWindow的列數(shù)
    window.setNumColumns(numColumns);
    // cursor移動到目標(biāo)位置
    if (cursor.moveToPosition(position)) {
        rowloop: do {
            // CursorWindow分配一行空間
            if (!window.allocRow()) {
                break;
            }
            // 遍歷列,將當(dāng)前行的每個列數(shù)據(jù)拷貝至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恢復(fù)原來的位置
    cursor.moveToPosition(oldPos);
}

下面只分析FIELD_TYPE_STRING類型數(shù)據(jù)的拷貝過程,也就是CursorWindowputString的實現(xiàn)。在分析之前先了解Native層CursorWindow的內(nèi)存布局。

  • CursorWindow的Header
    • freeOffset: CursorWindow空閑區(qū)域的偏移
    • firstChunkOffset: 第一個RowSlot的偏移
    • numRows: 行數(shù)
    • numColumns: 列數(shù)
  • RowSlotChunk
    • slots: 預(yù)分配的RowSlot,默認(rèn)100個
    • nextChunkOffset: 如果預(yù)分配的RowSlot不夠用,表示下一個RowSlotChunk在CursorWindow中的偏移
  • RowSlot
    • offset: 記錄一行數(shù)據(jù)在CursorWindow中的偏移
  • FieldSlot(記錄一個列數(shù)據(jù))
    • type: 列數(shù)據(jù)類型
    • 列類型為double/long
      • data.d/data.l: 值
    • 列類型為String/Blob
      • data.buffer.offset: String/Blob內(nèi)容在CursorWindow中的偏移
      • data.buffer.size: String/Blob內(nèi)容大小
    • 列類型為Null
      • data.buffer.offset: 0
      • data.buffer.size: 0
        下面看putString()的實現(xiàn)。
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;
    }
    // 調(diào)用CursorWindow的putString,這里sizeIncludingNull包含字符串結(jié)束符
    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(字節(jié)數(shù)組)或String, 單獨分配存儲空間
    uint32_t offset = alloc(size);
    if (!offset) {
        return NO_MEMORY;
    }
    // String內(nèi)容拷貝至分配的空間中
    memcpy(offsetToPtr(offset), value, size);
    // 記錄String數(shù)據(jù)信息
    fieldSlot->type = type;
    fieldSlot->data.buffer.offset = offset;
    fieldSlot->data.buffer.size = size;
    return OK;
}

至此,ContentProvider宿主進程的getWindow()分析完成,下面看ContentProvider客戶端收到回復(fù)后建立匿名共享內(nèi)存的過程。

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建立匿名共享內(nèi)存
    mWindowPtr = nativeCreateFromParcel(source);
    if (mWindowPtr == 0) {
        throw new CursorWindowAllocationException("Cursor window could not be "
                + "created from binder.");
    }
    mName = nativeGetName(mWindowPtr);
    mCloseGuard.open("close");
}

下面看nativeCreateFromParcel()的實現(xiàn)

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;
    // 匿名共享內(nèi)存文件描述符
    int ashmemFd = parcel->readFileDescriptor();
    if (ashmemFd == int(BAD_TYPE)) {
        result = BAD_TYPE;
    } else {
        // 獲取匿名共享內(nèi)存區(qū)域大小
        ssize_t size = ashmem_get_size_region(ashmemFd);
        if (size < 0) {
            result = UNKNOWN_ERROR;
        } else {
            // 創(chuàng)建文件描述符ashmemFd的拷貝
            int dupAshmemFd = ::dup(ashmemFd);
            if (dupAshmemFd < 0) {
                result = -errno;
            } else {
                // 映射虛擬地址空間用以讀取匿名共享內(nèi)存
                void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
                if (data == MAP_FAILED) {
                    result = -errno;
                } else {
                    // 創(chuàng)建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宿主進程之間就建立起了匿名共享內(nèi)存,此后ContentProvider客戶端只需訪問匿名共享內(nèi)存就能獲取Content數(shù)據(jù)。

getXxx(以getString為例分析)處理過程

下面從CursorWrapperInnergetString()開始分析

public String getString(int columnIndex) {
    // mCursor為BulkCursorToCursorAdapter類型的對象
    return mCursor.getString(columnIndex);
}

public String getString(int columnIndex) {
    // 檢查當(dāng)前的位置(Row)是否合法
    checkPosition();
    // 調(diào)用CursorWindow的getString
    return mWindow.getString(mPos, columnIndex);
}

public String getString(int row, int column) {
    acquireReference();
    try {
        // 從CursorWindow(匿名共享內(nèi)存)中讀取String
        return nativeGetString(mWindowPtr, row - mStartPos, column);
    } finally {
        releaseReference();
    }
}

下面看nativeGetString()的實現(xiàn)

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);
    // 根據(jù)行、列號找到對應(yīng)的FieldSlot
    CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
    if (!fieldSlot) {
        throwExceptionWithRowCol(env, row, column);
        return NULL;
    }

    // 讀取列數(shù)據(jù)類型
    int32_t type = window->getFieldSlotType(fieldSlot);
    if (type == CursorWindow::FIELD_TYPE_STRING) {
        size_t sizeIncludingNull;
        // 字符串內(nèi)容地址
        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;
    }
}

小結(jié)

參考

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容