腾讯微视Android高级岗:说说ContentProvider的启动过程

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.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.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§;

} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Unknown element under : " + tagName

  • " at " + mArchiveSourcePath + " "
  • parser.getPositionDescription());
    XmlUtils.skipCurrentTag(parser);
    continue;
    } else {
    outError[0] = "Bad element under : " + 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 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 providers) {
final ArrayList 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);
}
}

最后,如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。

小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值