接前一节《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 方法。