ContentProvider 组建主要用于 Android 系统中不同应用程序间的数据交换.例如应用程序 A 通过 ContentProvider 暴露内部的数据, 应用程序B 通过 ContentResolver 和 A 提供的 Uri 来操作(增, 删 改, 查) A 的数据.
如何创建一个contentPorvider
创建一个类继承ContentProvider,然后实现ContentProvider的抽象类
insert(Uri, ContentValues):插入新数据;
delete(Uri, String, String[]):删除已有数据;
update(Uri, ContentValues, String, String[]):更新数据;
query(Uri, String[], String, String[], String):查询数据;
onCreate():执行初始化工作;
getType(Uri):获取数据MIME类型。
ContentProvider的生命周期非常简单这里面只有一个onCreate方法
注册ContentProvider只需在AndroidManifest.xml配置文件中做如下声明
例如TelephonyProvider需要做如下声明,这样开机的时候PKMS进行扫描会把TelephonyProvider加入到对应应用的List<ProviderInfo>
/packages/providers/TelephonyProvider/AndroidManifest.xml
<provider android:name="TelephonyProvider"
android:authorities="telephony"
android:exported="true"
android:singleUser="true"
android:multiprocess="false" />
一般我们在contentProvider的实现类里面会定义一个内部类继承于SQLiteOpenHelper,用来创建操作具体的DB数据库文件,这里就不在详细介绍,之后再详细分析
其他进程或者应用想要访问contentPorvider暴露出来的数据库,必须通过ContentResolver来实现,应用必须获取它的ContentResolver类才可以通过它访问contentPorvider的相关操作。
这里举个例子/vendor/sprd/platform/frameworks/base/telephony/java/android/telephony/DmykTelephonyManager.java
这里通过context 获取到ContentResolver,然后执行qurey操作,返回cursor对象,包含了我们要查找的对象,然后进行数据解析。
Cursor cursor = mContext.getContentResolver().query(Uri.parse(APN_URI + "preferapn/subId/" + subId), new String[] {
532 "_id"}, where, null,orderBy);
533 if (cursor != null) {
534 if (cursor.getCount() > 0 && cursor.moveToFirst()) {
535 preferedId = cursor.getInt(0);
536 Log.d(TAG, "preferedId = " + preferedId + ", sub id = " + subId);
537 if (preferedId != -1) {
538 uri = Uri.parse(APN_URI + preferedId);
539 }
540 }
541 cursor.close();
542 }
ContextImpl:Activity,Service,Application都是ContextWrapper的子类。ContextWrapper里面有一个Context类型的成员变量mBase,当然它实际的类型是ContextImpl,所以我们上文提到的getContentResolver实现就是在ContextImpl中
ApplicationContentResolver:getContentResolver获取的是mContentResolver对象,实际上它就是ApplicationContentResolver的实例。它是ContentResolver的实现类。
ActivityThread:应用进程的主线程
ContentProviderNative:ContentProviderNative这个文件是Framework binder服务实现的标志实现,这里面ContentProviderNative 继承Binder实现IContentProvider接口,主要作为IContentProvider的service端。
ContentProviderProxy:实现IContentProvider接口,主要是IContentProvider服务,binder通信的代理断,我们可以通过ContentProviderNative.asInterface(iBinder)获取ContentProviderProxy的实例
Transport:ContentProviderNative的实现类,也是ContentProvider的内部类,作为IContentProvider binder服务server端的最后实现类。
ContentProviderHolder:在installProvider的时候会为要启动的provider创建,里面主要有两个变量一个是(IContentProvider)Provider,一个(IBinder)connection。
ContentProviderRecord:AMS管理provider信息的,每public一个contentProvider会创建一个,和ActivityRecord,serviceRecord类似,里面有如下几个重要变量
IContentProvider provider:在ActivityThread的installProvider()过程,会创建ContentProvider对象,那么也会创建Transport作为自己的binder服务端,放入到ContentProviderHolder的新实例中。经过binder传递到system_server 进程的便是ContentProvider.Transport的binder代理对象, 由publishContentProviders()过程完成赋值;
proc:记录provider所在的进程,是在publishContentProviders()过程完成赋值;
launchingApp:记录等待provider所在进程启动情况,getContentProviderImpl()过程执行创建进程之后赋值;
connections:记录该ContentProvider的所有连接信息,
添加连接过程:incProviderCountLocked
减少连接过程:decProviderCountLocked,removeDyingProviderLocked,cleanUpApplicationRecordLocked;
ContentProviderConnection:连接contentProvider与请求该provider所对应的进程
几个重要变量:
provider:目标provider所对应的ContentProviderRecord结构体;
client:请求该provider的客户端进程;
waiting:该连接的client进程正在等待该provider发布
ProviderInfo:PKMS解析应用后,会为每个ContentProvider声明创建一个该对象,写入相关信息
ProviderClientRecord:在AT里面记录新创建的Provider的信息,它的contentProvider,binder代理对象,ContentProviderHolde对象,UIR的auths对象
Provider进程启动方式跟之前写过的AMS启动Activity类似,都需要先调用AMS.startProcessLocked()方法创建应用进程,应用进程启动后ActivityThread都会执行attached AMS的操作。
我们便从attached AMS的操作开始跟踪后续的发布过程。
AT-ActivityThread
AT经过binder调用AMS的attachApplicationLocked方法,
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
//调用generateApplicationProvidersLocked获取对应app的ProviderInfo list,这个在开机的时候PKMS扫描解析出来声明的contentProvider
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {//检查app是否正在launch,正常刚启动的进程为true
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);//发生Provider public超时监测
didSomething = true;
}
//调用对端应用主线程 AT.bindApplication
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
//从PKMS获取app对应进程的Provider list
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
| MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
.getList();
} catch (RemoteException ex) {
}
int userId = app.userId;
if (providers != null) {
int N = providers.size();
app.pubProviders.ensureCapacity(N + app.pubProviders.size());//pubProviders进行list扩容
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
// 判断对应ProviderInfo是单独进程的,同时不是系统用户
providers.remove(i);//从list移除ProviderInfo
N--;
i--;
continue;
}
//创建对应Provider的组件对象,包括包名和contentprovider名
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
//mProviderMap是AMS存储ContentProvider各种对应关系的类,这里主要是把ComponentName 和ContentProviderRecord对应起来,存入HashMap表。
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
//pubProviders是ProcessRecord管理要public的Provider的list表
app.pubProviders.put(cpi.name, cpr);
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
mProcessStats);
}
notifyPackageUse(cpi.applicationInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
}
}
return providers;
}
ActivityThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial) {
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;//通过data 放入providers列表
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
data.buildSerial = buildSerial;
sendMessage(H.BIND_APPLICATION, data);//发送BIND_APPLICATION消息调用到handleBindApplication(data)
}
private void handleBindApplication(AppBindData data) {
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {//providers列表不为null
startTime = CheckTime.getTime();
installContentProviders(app, data.providers);//初始化安装Provider.
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
CheckTime.checkTime(startTime, "handleBindApplication : installContentProviders");
}
}
}
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
遍历传入的providers list,调用installProvider安装对应ProviderInfo的Provider
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
//调用AMS 的publishContentProviders方法,public Provider,传入的参数是results
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
if (SystemProperties.get("persist.support.securetest").equals("1"))
{
// 下面逻辑主要是把proviedname数组的这些Provider,他们的binder 代理段注册到ServiceManager,这样可以直接从ServiceManager通过authority获取对应的Provider代理端
// for(IActivityManager.ContentProviderHolder holder : results)
for(ContentProviderHolder holder : results)
{
Log.i(TAG , "add content provider authority:" + holder.info.authority + ", provider binder:" + holder.provider.asBinder());
String proviedname [] = {"sms","mms","mms-sms","call_log","contacts;com.android.contacts","icc","media",null} ;
for (int i = 0 ; proviedname[i] != null ; i++)
{
if (proviedname[i].equals(holder.info.authority))
{
ServiceManager.addService(holder.info.authority, holder.provider.asBinder());
}
}
}
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
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) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
if (context.getPackageName().equals(ai.packageName)) {
//AT的context的包名和ProviderInfo中包名相同
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
//
c = mInitialApplication;
} else {
try {
//如果前面的都不符合要求,创建context
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
if (info.splitName != null) {
try {
c = c.createContextForSplit(info.splitName);
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
}
try {
final java.lang.ClassLoader cl = c.getClassLoader();
通过反射创建目标ContentProvider对象
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();、
//获取localProvider的binder代理端Transport
provider = localProvider.getIContentProvider();
....
//回调目标ContentProvider.onCreate方法,ContentProvider.this.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);
}
ContentProviderHolder retHolder;
synchronized (mProviderMap) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
把新创建的localProvider,创建一个对应的ProviderClientRecord,并放入到mLocalProvidersByName 和mLocalProviders map表中
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;
} ....
return retHolder;
}
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
//通过caller获取对应的应用进程对象ProcessRecord
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
.....
final long origId = Binder.clearCallingIdentity();
final int N = providers.size();
for (int i = 0; i < N; i++) {
//遍历providers列表,取出每个ContentProviderHolder对象
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
//之前这些要发布的Provider放到了pubProviders列表,此处根据name取出对应的ContentProviderRecord对象
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
//还是根据包名和Provider名字创建组件名字实例
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
//把创建的组件实例和ContentProviderRecord实例以键值对的形式存入mProviderMap的putProviderByClass hashmap表。
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
//将URI的authority信息解析成字符串数组,也存入putProviderByName map表
mProviderMap.putProviderByName(names[j], dst);
}
//然后把这些Provider的ContentProviderRecord实例从launchingCount列表移除
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--;
}
}
//移除public 超时信息
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
//唤醒客户端的wait等待方法,可能有些进程正在等待Provider进程的公布。
dst.notifyAll();
}
//更新当前Provider进程的adj
updateOomAdjLocked(r, true);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}
第一章介绍过,我们先获取ContentResolver对象进行相关操作。
我们一般都是获取当前应用的context,然后调用getContentResolver,实际的执行则是在ContextImpl实现的
ContextImpl.java
public ContentResolver getContentResolver() {
return mContentResolver;
}
那么mContentResolver对象在那赋值的呢
实在ContextImpl构造函数里面
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
前面介绍过ApplicationContentResolver就是ContentResolver的实现类
ApplicationContentResolver没有复写query,所以还是调用ContentResolver.query
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
//调用 AT.acquireExistingProvider查询本地的Provider,如果没有则调用AMS查询对应的Provider的代理对象
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 {
//通过调用Provider代理端,访问Provider服务提供者的query方法
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 远程进程死亡,处理unstable provider死亡过程
unstableProviderDied(unstableProvider);
//unstable类型死亡后,再创建stable类型的provider
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
//再次执行查询操作
qCursor = stableProvider.query(
mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
/强制执行查询操作,可能会失败并跑出RuntimeException
qCursor.getCount();
//查询持续时间
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
// Wrap the cursor object into CursorWrapperInner object.
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
创建对象CursorWrapperInner
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);
}
}
}
ContentResolver.acquireUnstableProvider最后的实现都在ApplicationContentResolver,对应的调用都是分别调用如下
mMainThread.acquireExistingProvid
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
//根据传入的auth, userId创建一个对应的key
final ProviderKey key = new ProviderKey(auth, userId);
然后根据key从mProviderMap查询对应的ProviderClientRecord
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
从获取的ProviderClientRecord中获取IContentProvider 实例mProvider也就是本地Provider的代理对象
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
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");
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// 增加引用计数
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
incProviderRefLocked(prc, stable);
}
return provider;
}
}
ContentResolver.acquireProvider
最后的实现都在ApplicationContentResolver,对应的调用都是分别调用如下
mMainThread.acquireProvider
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
//通过AT mProviderMap 获取 ProviderClientRecord,然后在找出对应的IContentProvider对象
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
ContentProviderHolder holder = null;
try {
//向AMS传入auth,userId等信息,查询我要查询的Provider对应的ContentProviderHolder实例
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,如果传入的holder不为null则主要实现增加引用计数
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
// 这样我们就获取了IContentProvider 实例provider
return holder.provider;
}
它主要在getContentProviderImpl中实现的
这里面的代码不少,我主要把里面重要的内容摘取出来,主要先关注查询的一个大概流程
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
ProcessRecord r = null;
获取调用应用在AMS的ProcessRecord实例
r = getRecordForAppLocked(caller);
根据name,userId获取要查询的Provider在AMS的ContentProviderRecord实例,下面会根据不同场景选择userid,这里不做赘述,只贴出主要方法
cpr = mProviderMap.getProviderByName(name, requestedFromAppClone ? UserHandle.USER_OWNER : userId);
//providerRunning 作为Provider进程是否启动并在AMS发布的一个判断值
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
下面我会有两种情况,Provider进程已经启动,或者没启动
我们先看
Provider进程已经启动的情况:
cpi = cpr.info;
if (r != null && cpr.canRunHere(r)) {
//当允许运行在调用者进程且已发布,则直接返回
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
//增加引用计数
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// 更新LUR队列
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
}
当Provider进程没有启动,则启动
//根据authority,获取ProviderInfo对象
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
//当provider并没有处于mLaunchingProviders队列,则启动它
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
最后会等待Provider发布,直到发布后才退出