ContentProvider增删改查的过程

说明:基于API 26的源码分析

ContentProvider增删改查过程分析

1.增删改查的使用实例

1
2
3
4
5
ContentResolver cr = context.getContentResolver();
cr.insert(uri,contentValues);
cr.delete(uri, where,selectionArgs);
cr.update(uri,values, where,selectionArgs);
cr.query(uri,projection, selection, selectionArgs, sortOrder, cancellationSignal);

2.类图

content_provider_04

##3.代码分析

3.1 Context的getContentResolver方法

通常调用getContentResolver的context是指application,或者activity,或者service, 而这三者都是继承ContextWrapper, ContextWrapper的getContentResolver()实质是调用ContextImpl的getContentResolver()。看看ContextImpl相关的源码。

1
2
3
4
5
6
7
8
9
10
11
12
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
@NonNull LoadedApk packageInfo, @Nullable String splitName,
@Nullable IBinder activityToken, @Nullable UserHandle user, int flags,
@Nullable ClassLoader classLoader) {
//ContextImpl构造器,省略无关代码
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}

@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}

从上面代码可知, getContentResolver()返回实现类是ApplicationContentResolver类。

3.2 ContentProvider的插入

第一步:ContentResolver的insert方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, @Nullable ContentValues values) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
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);
}
}

先调用acquireProvider获取IContentProvider, 然后调用insert方法插入数据,并返回uri,最后在finnaly里调用releaseProvider()释放provider。

第二步: ApplicationContentResolver的acquireProvider方法

第一步中acquireProvider方法真正实现是ApplicationContentResolver。

1
2
3
4
5
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,ContentProvider
.getAuthorityWithoutUserId(auth),resolveUserIdFromAuthority(auth), true);
}

再看ActivityThread的acquireProvider方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}

ContentProviderHolder holder = null;
try {
holder = ActivityManager.getService().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;
}

holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}

先调用acquireExistingProvider获取存在的IContentProvider, 获取到provider不为null,立马返回。如果为null, 调用ActivityManager.getService().getContentProvider()在AMS进程中获取其他应用共享的contentprovider, 没获取立马返回null。如果不为null,调用installProvider方法。 在这里installProvider(),acquireExistingProvider()其实有对立的作用,有一个map存储holder,调用acquireExistingProvider()检查map里有没有holder,如果没有再调用installProvider(),把holder放到map里。下面再具体看一下:

接着看ActivityThread的acquireExistingProvider方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
......
return provider;
}
}

用contentprovider的authority和userId组成ProviderKey,ProviderKey是mProviderMap的Key, 先从mProviderMap获取ProviderClientRecord。ProviderClientRecord存储着IContentProvider, ContentProviderHolder。如果mProviderMap里没有返回null。接着调用ActivityManager.getService().getContentProvider()在AMS进程中获取其他应用共享的contentprovider。

接着看ActivityThread的installProvider方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
.......//省略部分代码
}else{
provider = holder.provider;
}
ContentProviderHolder retHolder;
synchronized (mProviderMap) {
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 ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
ActivityManager.getService().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}

return retHolder;
}

此时调用installProvider方法的holder不为null, localProvider为本应用的contentProvider, 此时为null,所有直接到else下面的逻辑,先在mProviderRefCountMap中获取ProviderClientRecord,没有就调用installProviderAuthoritiesLocked方法生成ProviderClientRecord,并生成ProviderRefCount放入mProviderRefCountMap这个Map中,还会把ProviderClientRecord放入mProviderMap这个Map中。

第三步: Transport的insert方法

Transport是接口IContentProvider实现类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
validateIncomingUri(uri); // 验证Uri
int userId = getUserIdFromUri(uri); // userId,用于判断是哪个用户。(针对于Android的多用户模式)
uri = maybeGetUriWithoutUserId(uri);
if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { //验证权限
return rejectInsert(uri, initialValues);
}
final String original = setCallingPackage(callingPkg);
try {
return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId); // 调用ContentProvider的insert方法。
} finally {
setCallingPackage(original);
}
}

这个方法主要调用ContentProvider.this.insert(),也就是开发者自定义ContentProvider需要实现的方法。

3.3 ContentProvider的查询

第一步 ContentResolver的qurey()

1
2
3
4
5
6
7
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder);// selection, selectionArgs, sortOrder存入Bundle中
return query(uri, projection, queryArgs, cancellationSignal);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
//获取不稳定的IContentProvider
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(); // 创建远程取消信号,remoteCancellationSignal是客户端的Proxy,用于跨进程取消查询
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
// 查询获取Cursor
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 远程进程死了,重新尝试后去稳定的IContentProvider
// 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
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(
mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}

// Force query execution. Might fail and throw a runtime exception here.
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
// 包装cursor成CursorWrapperInner
// Wrap the cursor object into CursorWrapperInner object.
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
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) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}

获取IContentProvider,调用IContentProvider的query方法获取查询的Cursor。不夸进程时和跨进程是不一致。

IContentProvider当没有跨进程时,实例是ContentProvider的内部类Transport;当跨进程时,是通过ActivityManager.getService().getContentProvider()获取的ContentProviderHolder,ContentProviderHolder里有个成员变量IContentProvider, 而这个IContentProvider的实例为ContentProviderProxy; 查询获取的Cursor,如果不跨进程就是重写ContentProvider的query方法返回的真正实例。跨进程时,下面源码分析跨进程过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//ContentProviderProxy的query方法如下:
@Override
public Cursor query(String callingPkg, Uri url, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
throws RemoteException {
//BulkCursorToCursorAdaptor,用于装载远程返回结果,BulkCursorToCursorAdaptor是Cursor实例
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
//创建用于传输的Parcel实例data, 创建用于另外一个进程回应的Parcel实例reply
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);//写入接口Token

data.writeString(callingPkg);//写入包名
url.writeToParcel(data, 0);//写入Uri
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]); // 写入projection数组
}
data.writeBundle(queryArgs);//写入查询参数
//daptor.getObserver().asBinder() 转成binder 写入data。
//binder是充当服务端,传递给客户端调用
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(
cancellationSignal != null ? cancellationSignal.asBinder() : null);

//传输data给另一个进程
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);

//读取回应的Exception
DatabaseUtils.readExceptionFromParcel(reply);

if (reply.readInt() != 0) {
//读取Cursor描述符
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
//传入Cursor描述符完成初始化adaptor
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
//返回adapter给客户端
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//ContentProviderNative是个抽象类,实现是Transport
//ContentProviderNative的onTransact相关源码:
switch (code) {
case QUERY_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);

String callingPkg = data.readString();
//读取客户端uri
Uri url = Uri.CREATOR.createFromParcel(data);

// 读取客户端 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();
}
}
//读取客户端查询参数
Bundle queryArgs = data.readBundle();
//获取到客户端传来的Binder,通过调用IContentObserver.Stub.asInterface()产生一个代理,用于跨进程调用
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());

//根据查询参数查询,实质调用ContentProvider的 query(),由ContentProvider子类实现
Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;

try {
//把查询得到的cusor转换为CursorToBulkCursorAdaptor
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
//adapter获取到BulkCursorDescriptor描述符
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;

reply.writeNoException();
reply.writeInt(1);
//Cusor描述符写入reply给回客户端进程
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;
}

跨进程传递数据通过Parcel,Parcel承载数据类型有限,基本类型,实现Parcelable的类型。实现ContentProvider的query()返回是Cursor接口不能保证是Parcel能承载的类型。所以通过CursorToBulkCursorAdaptor把cursor包装,再转成BulkCursorDescriptor, BulkCursorDescriptor是实现Parcelable的,可以用于跨进程传递。客户端获取到BulkCursorDescriptor,用BulkCursorToCursorAdaptor把BulkCursorDescriptor封装起来, BulkCursorToCursorAdaptor是实现了Cursor, 返回adapter即可。

Loading comments box needs to over the wall