一、引言
ContentProvider作为Android的四大组件之一,其主要的作用是通过Binder向其他组件或者其他应用提供数据。它的底层实现方式也是Binder,但是它的使用方法又比较简单。原因是系统为我们做了封装,而我们无须关心底层细节就能轻松的实现进程间的通信。
ContentProvider的应用还是挺广泛的,比如我们应用中获取通讯录、获取短信、获取手机通话记录等,都是通过ContentProvider来进行的。
既然ContentProvider这么重要,我们有必要从源码的角度深挖一下ContentProvider的启动过程。
二、源码分析
1、ContentProvider的创建与初始化
在具体分析源码之前,我们大致看一下ContentProvider的整个启动过程的示意图,如下所示:
App启动后,会调用ActivityThread的main方法,接着在main方法中创建了ActivityThread对象,并调用了它的attach方法。在attach方法中远程调用AMS的attachApplication方法,该方法中又远程调用PMS的queryContentProviders方法获取应用注册的Provider信息,然后调用ApplicationThread的bindApplication方法将Provider信息传递过去。在ApplicationThread中通过makeApplication生成Application对象,并调用installContentProviders方法初始化并加载ContentProvider,然后调用Application对象的onCreate方法,应用就这样跑起来了。
下面我们具体分析上述的每一个步骤。
首先是App启动,调用了ActivityThread的main方法,如下所示:
public static void main(String[] args) {
...省略
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
}
main方法中,创建了ActivityThread对象,然后调用了该对象的attach方法,如下所示:
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...省略
} else {
...省略
}
...省略
}
系统的应用我们不作分析,而对于非系统应用,ActivityManager.getService()获取到一个IActivityManager对象,它是一个Binder对象,通过它调用attachApplication方法实际上就是远程调用了ActivityManagerService的attachApplication方法,如下所示:
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
attachApplication方法又调用了attachApplicationLocked方法,如下所示:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...省略
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
app.killed = false;
app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
//获取应用中注册的ContentProvider数据
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
}
checkTime(startTime, "attachApplicationLocked: before bindApplication");
try {
...省略
// If we were asked to attach an agent on startup, do so now, before we're binding
// application code.
if (agent != null) {
thread.attachAgent(agent);
}
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
if (app.instr != null) {
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);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
...省略
}
...省略
return true;
}
在attachApplicationLocked方法中,主要流程分为两步:
- 在正常模式下,调用了generateApplicationProvidersLocked方法获取注册的ContentProvider信息。
- 将上一步中的ContentProvider信息作为参数,远程调用了ApplicationThread的bindApplication方法。
我们首先看第一步,generateApplicationProvidersLocked方法如下所示:
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
//远程调用PMS获取应用中注册的ContentProvider信息
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;
...省略
return providers;
}
在上述方法中,AppGlobals.getPackageManager()方法返回的是IPackageManager,调用了它的queryContentProviders方法。这是一个Binder对象,其实际调用的是PackageManagerService的queryContentProviders方法,如下所示:
public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
int uid, int flags, String metaDataKey) {
final int callingUid = Binder.getCallingUid();
final int userId = processName != null ? UserHandle.getUserId(uid)
: UserHandle.getCallingUserId();
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForComponent(flags, userId, processName);
ArrayList<ProviderInfo> finalList = null;
// reader
synchronized (mPackages) {
final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator();
while (i.hasNext()) {
final PackageParser.Provider p = i.next();
PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
if (ps != null && p.info.authority != null
&& (processName == null
|| (p.info.processName.equals(processName)
&& UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
&& mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
// See PM.queryContentProviders()'s javadoc for why we have the metaData
// parameter.
if (metaDataKey != null
&& (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
continue;
}
final ComponentName component =
new ComponentName(p.info.packageName, p.info.name);
if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
continue;
}
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
ProviderInfo info = PackageParser.generateProviderInfo(p, flags,
ps.readUserState(userId), userId);
if (info != null) {
finalList.add(info);
}
}
}
}
if (finalList != null) {
Collections.sort(finalList, mProviderInitOrderSorter);
return new ParceledListSlice<ProviderInfo>(finalList);
}
return ParceledListSlice.emptyList();
}
queryContentProviders方法很长,但是其主要做的事情是,遍历了mProviders.mProviders中的值,而mProviders.mProviders的一个ArrayMap,value为PackageParse.Provider对象。所以,我们需要知道mProviders.mProviders是在哪里被赋值的,最后找到了PackageManagerService.ProviderIntentResolver的addProvider方法,如下所示:
public final void addProvider(PackageParser.Provider p) {
if (mProviders.containsKey(p.getComponentName())) {
Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
return;
}
mProviders.put(p.getComponentName(), p);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " "
+ (p.info.nonLocalizedLabel != null
? p.info.nonLocalizedLabel : p.info.name) + ":");
Log.v(TAG, " Class=" + p.info.name);
}
final int NI = p.intents.size();
int j;
for (j = 0; j < NI; j++) {
PackageParser.ProviderIntentInfo intent = p.intents.get(j);
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
if (!intent.debugCheck()) {
Log.w(TAG, "==> For Provider " + p.info.name);
}
addFilter(intent);
}
}
该方法中,将参数中的PackageParser.Provider对象put了进来,而PackageParser.Provider对象存储的就是每一个ContentProvider的信息。在PackageManagerService的commitPackageSettings方法中调用了上述方法,commitPackageSettings方法如下所示:
private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
...省略
//存储ContentProvider的信息
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName);
mProviders.addProvider(p);
p.syncable = p.info.isSyncable;
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
p.info.authority = null;
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.syncable) {
// We only want the first authority for a provider to possibly be
// syncable, so if we already added this provider using a different
// authority clear the syncable flag. We copy the provider before
// changing it because the mProviders object contains a reference
// to a provider that we don't want to change.
// Only do this for the second authority since the resulting provider
// object can be the same for all future authorities for this provider.
p = new PackageParser.Provider(p);
p.syncable = false;
}
if (!mProvidersByAuthority.containsKey(names[j])) {
mProvidersByAuthority.put(names[j], p);
if (p.info.authority == null) {
p.info.authority = names[j];
} else {
p.info.authority = p.info.authority + ";" + names[j];
}
if (DEBUG_PACKAGE_SCANNING) {
if (chatty)
Log.d(TAG, "Registered content provider: " + names[j]
+ ", className = " + p.info.name + ", isSyncable = "
+ p.info.isSyncable);
}
} else {
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
Slog.w(TAG, "Skipping provider name " + names[j] +
" (in package " + pkg.applicationInfo.packageName +
"): name already used by "
+ ((other != null && other.getComponentName() != null)
? other.getComponentName().getPackageName() : "?"));
}
}
}
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(p.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
}
//存储Service的信息
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName);
mServices.addService(s);
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(s.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
}
//存储BroadcastReceiver的信息
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName);
mReceivers.addActivity(a, "receiver");
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
//存储Activity的信息
N = pkg.activities.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName);
mActivities.addActivity(a, "activity");
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r);
}
...省略
}
可以看到,commitPackageSettings方法中不仅仅存储了ContentProvider的信息,还存储了Service、BroadcastReceiver、Activity等信息,而PackageParser.Provider对象是遍历PackageParser.Package的providers获取的,而PackageParser.Package的providers就是通过解析AndroidManifest.xml得到的。PackageParser的parseBaseApplication方法就是解析方法,如下所示:
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
...省略
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.services.add(s);
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.providers.add(p);
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Unknown element under <application>: " + tagName
+ " at " + mArchiveSourcePath + " "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
} else {
outError[0] = "Bad element under <application>: " + tagName;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
}
}
...省略
return true;
}
可以看到对于AndroidManifest中的tagName为provider,则解析其中的信息并生成PackageParser.Provider对象。
通过PMS获取ContentProvider列表信息的流程到此结束,通过上述分析,我们也验证了自定义的ContentProvider必须在AndroidManifest中注册这样的一个结论。
我们继续回到AMS的attachApplicationLocked方法中,在拿到了应用注册的ContentProvider信息后,远程调用了ApplicationThread的bindApplication方法,如下所示:
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) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = 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);
}
注意:参数中的上述的providers就是从PMS中获取的ContentProvider信息。
该方法发送了一个消息,消息ID是H.BIND_APPLICATION。在mH对象的handleMessage方法中处理该消息,并调用handleBindApplication方法,如下所示:
private void handleBindApplication(AppBindData data) {
...省略
Application app;
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
try {
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
//ContentProvider列表不为空
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers); //初始化并加载ContentProvider
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
//调用Application的onCreate方法
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} finally {
// If the app targets < O-MR1, or doesn't change the thread policy
// during startup, clobber the policy to maintain behavior of b/36951662
if (data.appInfo.targetSdkVersion <= Build.VERSION_CODES.O
|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
StrictMode.setThreadPolicy(savedPolicy);
}
}
...省略
}
在handleBindApplication方法中,判断如果ContentProvider列表不为空,则调用installContentProviders方法,如下所示:
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
对于传递过来的ContentProvider列表,遍历该列表,取出每一个ProviderInfo对象,并调用installProvider方法(第二个参数传过来的是null)。如下所示:
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) {
if (DEBUG_PROVIDER || noisy) {
Slog.d(TAG, "Loading provider " + info.authority + ": "
+ info.name);
}
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;
}
if (info.splitName != null) {
try {
c = c.createContextForSplit(info.splitName);
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
}
try {
//通过类生成器生成了ContentProvider对象
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
...省略
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 {
...省略
}
...省略
return retHolder;
}
由于上一个方法中传递进来的holder为null,则走holder == null的逻辑,其中通过类生成器生成了ContentProvider对象,并且调用了ContentProviderProvider对象的attachInfo方法,attachInfo方法调用了另一个attachInfo重载方法,如下所示:
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
if (mContext == null) {
mContext = context;
if (context != null) {
mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
}
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
ContentProvider.this.onCreate();
}
}
在该方法中执行了ContentProvider对象的onCreate方法。这也证明了一个结论:ContentProvider的onCreate方法是在UI线程执行的。
小结:通过上述的源码分析,我们知道了ContentProvider是在AndroidManifest中注册,并且在App启动时通过反射的形式创建的,创建后并且调用了每一个ContentProvider对象的onCreate方法。然后调用了Application对象的onCreate方法,整个App就这样运行起来了。
2、ContentProvider的调用
上面分析了ContentProvider对象是如何创建和初始化的,承接上面的内容,我们继续分析外部应用是如何调用ContentProvider的CRUD方法来和ContentProvider交互的。
我们拿其中的一个方法query进行分析,其他方法的流程与之类似,就不再重复分析了。
我们知道,在客户端应用中,调用ContentProvider的query方法是通过Context的getContentResolver().query方法来实现的,而Context的实现者对象是ContextImpl,其getContentResolver方法如下所示:
public ContentResolver getContentResolver() {
return mContentResolver;
}
很简单的返回了一个ContentResolver对象,而上面的mContenResolver实际类型是ApplicationContentResolver,所以getContentResolver().query方法实际上执行的是ApplicationContentResolver.query方法,而ApplicationContentResolver并没有重写query方法,所以query方法还是在ContentResolver中实现,如下所示:
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 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 {
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 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);
// 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;
}
...省略
}
query方法中,获取数据的步骤主要有以下两步:
- 通过acquireUnstableProvider方法获取IContentProvider,这是Binder对象。
- 通过该Binder对象远程调用ContentProvider的query方法得到Cursor对象。
我们先来看第一步,acquireUnstableProvider方法如下所示:
public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
String auth = uri.getAuthority();
if (auth != null) {
return acquireUnstableProvider(mContext, uri.getAuthority());
}
return null;
}
一上来就判断了Uri的合法性,如果Uri的Scheme没有以SCHEME_CONTENT开头,则返回null。SCHEME_CONTENT的值是"content",说明了和ContentProvider交互的Uri必须以"content"作为scheme。然后调用了acquireUnstableProvider方法,acquireUnstableProvider在子类中实现,即在ApplicationContentResolver中实现,如下所示:
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
acquireUnstableProvider方法又调用了ActivityThread的acquireProvider方法,如下所示:
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 {
//缓存中没有,远程调用AMS的getContentProvider方法返回IContentProvider对象
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;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
如果缓存中有IContentProvider对象,则从缓存中获取;否则从远程调用AMS获取IContentProvider对象。
小结:这里说明了和ContentProvider交互是进程间的通信,而中间桥梁就是AMS。
通过AMS拿到了服务端应用的ContentProvider的代理对象IContentProvider,返回到上面的query方法,通过IContentProvider对象调用其query方法返回了Cursor对象给到客户端调用者。
我们知道,IContentProvider对象的实现者是ContentProvider.Transport。因此客户端通过IContentProvider远程调用query方法,实际上调用的是ContentProvider.Transport的query方法,如下所示:
public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
if (projection != null) {
return new MatrixCursor(projection, 0);
}
Cursor cursor = ContentProvider.this.query(
uri, projection, queryArgs,
CancellationSignal.fromTransport(cancellationSignal));
if (cursor == null) {
return null;
}
// Return an empty cursor for all columns.
return new MatrixCursor(cursor.getColumnNames(), 0);
}
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
uri, projection, queryArgs,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
可以看到,ContentProvider.Transport的query方法最终调用了ContentProvider对象的query方法,最终的结果再通过Binder返回给客户端调用者。这样就完成了客户端远程调用ContentProvider的query方法的整个过程。
三、总结
客户端应用和服务端应用的ContentProvider交互是进程间的通信,其底层是通过Binder实现的。
ContentProvider对象在App启动时会创建并初始化,其onCreate方法是运行在服务端的主进程的;外部应用调用ContentProvider的CRUD方法是进程间的调用,是运行在系统的Binder进程的。