AcquireProvider (Android AOSP 6.0.1) acquireProvider (Android AOSP 6.0.1) acquireProvider (Android AOSP 6.0.1) acquireProvider

Below is a sequence diagram of the content provider’s INSERT process analysis.



frameworks/base/core/java/android/content/ContentResolver.java

public abstract class ContentResolver {...public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
        Preconditions.checkNotNull(url, "url");
        // 1. Obtain the remote proxy class
        IContentProvider provider = acquireProvider(url);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URL " + url);
        }
        try {
            long startTime = SystemClock.uptimeMillis();
            // 2. Insert data
            Uri createdRow = provider.insert(mPackageName, url, values);
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogUpdateToEventLog(durationMillis, url, "insert".null /* where */);
            return createdRow;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally{ releaseProvider(provider); }}... }Copy the code

We learned from the previous section that Provider is a remote proxy class that implements IContentProvider. Go back to the ActivityThread installProvider method to find the corresponding provider. The provider is called the localProvider getIContentProvider () method return values.

frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {...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) {   
            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}}if (c == null) {
                Slog.w(TAG, "Unable to get context for package " +
                      ai.packageName +
                      " while loading content provider " +
                      info.name);
                return null;
            }
            try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                // Create the ContentProvider instance
                localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();
                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);
                // The correct context needs to be created for this provider. This is going to call the ContentProvider onCreate method.
                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 {
            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);
            IBinder jBinder = provider.asBinder();
            if(localProvider ! =null) {
                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);
                    // Here the Provider member of the ContentProviderHolder object is assigned a value
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else{... }}returnretHolder; }... }Copy the code

Now go to the ContentProvider getIContentProvider() method. We see that the actual getIContentProvider method returns a Transport object. The Transport class inherits from ContentProviderNative, so it must be inferred that ContentProviderNative implements the IContentProvider interface.

frameworks/base/core/java/android/content/ContentProvider.java

public abstract class ContentProvider implements ComponentCallbacks2 {...private Transport mTransport = newTransport(); .class Transport extends ContentProviderNative {...@Override
        public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
            validateIncomingUri(uri);
            int userId = getUserIdFromUri(uri);
            uri = getUriWithoutUserId(uri);
            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
                return rejectInsert(uri, initialValues);
            }
            final String original = setCallingPackage(callingPkg);
            try {
                // The insert method of the external class ContentProvider object is called here.
                return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId);
            } finally{ setCallingPackage(original); }}... }...public IContentProvider getIContentProvider(a) {
        returnmTransport; }... }Copy the code

Let’s look at the implementation of ContentProviderNative. The previous section mentioned that the ContentProviderHolder object returned from the ActivityManagerService getContentProviderImpl method ends up in the ActivityManagerProxy The getContentProvider function deserializes the ContentProviderHolder object. Particular attention is paid to the handling of provider members in serialization and deserialization, which calls Provider.asbinder (), When deserialization ContentProviderNative asInterface get is a ContentProviderProxy proxy objects.

frameworks/base/core/java/android/content/ContentProviderNative.java

abstract public class ContentProviderNative extends Binder implements IContentProvider {...static public IContentProvider asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IContentProvider in =
            (IContentProvider)obj.queryLocalInterface(descriptor);
        if(in ! =null) {
            return in;
        }

        return newContentProviderProxy(obj); }...public IBinder asBinder(a)
    {
        return this; }}Copy the code

Now that it’s clear that the object that implements the IContentProvider interface is actually of type ContentProviderProxy, call its INSERT method as follows:

frameworks/base/core/java/android/content/ContentProviderNative.java

final class ContentProviderProxy implements IContentProvider
{
    public ContentProviderProxy(IBinder remote)
    { mRemote = remote; }...public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(IContentProvider.descriptor);

            data.writeString(callingPkg);
            url.writeToParcel(data, 0);
            values.writeToParcel(data, 0);

            mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);

            DatabaseUtils.readExceptionFromParcel(reply);
            Uri out = Uri.CREATOR.createFromParcel(reply);
            return out;
        } finally{ data.recycle(); reply.recycle(); }}... }Copy the code

Eventually the Binder mechanism calls the Transport Insert method, which inside ends up calling the insert method of its external ContentProvider object, That’s the insert method in the Demo.