Android AOSP 6.0.1 内容提供者 insert 流程分析

263 阅读3分钟

接前一节《Android AOSP 6.0.1 内容提供者 acquireProvider 流程分析》分析了 acquireProvider 函数流程,今天将重心转移到 insert 函数。

下面是内容提供者 insert 流程分析时序图。
在这里插入图片描述
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.获取远程代理类 
        IContentProvider provider = acquireProvider(url);
        if (provider == null) {
            throw new IllegalArgumentException("Unknown URL " + url);
        }
        try {
            long startTime = SystemClock.uptimeMillis();
            // 2.插入数据
            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);
        }
    }
    ......
}

通过前一节我们已经知道 provider 是一个实现了 IContentProvider 的远程代理类,具体一点要回到 ActivityThread installProvider方法,找到对应的 provider。provider 是调用了 localProvider.getIContentProvider() 方法得到的返回值。

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();
                // 创建 ContentProvider 实例
                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);
                // 需要为此提供者创建正确的上下文。这里会调用 ContentProvider 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 {
            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);
                    // 此处 ContentProviderHolder 对象 provider 成员已赋值
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {
                ......
            }
        }

        return retHolder;
    }
    ......
}

现在转入 ContentProvider getIContentProvider() 方法。我们看到实际 getIContentProvider 方法返回的是一个 Transport 对象。Transport 类继承自 ContentProviderNative,一定可以推测出 ContentProviderNative 类实现了 IContentProvider 接口。

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

public abstract class ContentProvider implements ComponentCallbacks2 {
    ......
    private Transport mTransport = new Transport();
    ......
    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 {
                // 此处调用了外部类 ContentProvider 对象的 insert 方法。
                return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId);
            } finally {
                setCallingPackage(original);
            }
        }
        ......
    }
    ......
    public IContentProvider getIContentProvider() {
        return mTransport;
    }
    ......
}

接下来看看 ContentProviderNative 的实现。上一节提到从 ActivityManagerService getContentProviderImpl 方法返回 ContentProviderHolder 对象最终在 ActivityManagerProxy getContentProvider 函数中反序列化得到 ContentProviderHolder 对象。这里要特别关注序列化和反序列化中对 provider 成员的处理,序列化时候调用了 provider.asBinder() ,反序列化的时候 ContentProviderNative.asInterface 得到是一个 ContentProviderProxy 代理对象。

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 new ContentProviderProxy(obj);
    }
    ......
    public IBinder asBinder()
    {
        return this;
    }
}

现在已经明确了实现 IContentProvider 接口的对象实际是 ContentProviderProxy 类型,调用其 insert 方法如下:

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();
        }
    }
    ......
}

最终 Binder 机制会调用 Transport insert 方法,Transport insert 方法内部最终调用了其外部类 ContentProvider 对象的 insert 方法,也就是 Demo 中对应的 insert 方法。