ContentProvider是内容提供者,对外提供数据。内部运行依赖Binde机制。想要自己写一个ContentProvider向外部提供数据,需要继承ContentProvider并重写一下六个方法,在ContentProvider中提供了增删改查的方法,一般这个增删改查会通过SqliteDataBase这个数据库的方式对外提供增删改查的功能。也可以不这么做。
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
需要在AndroidManifest.xml中去注册:
authorities 相当于是个地址
permission 用于控制权限
<provider
android:name=".provider.BookProvider"
android:authorities="com.sososeen09.knowledge.provider.book"
android:permission="com.sososeen09.PROVIDER"
android:process=":provider"/>
其它客户端查询,需要用到ContentResolver对象,ContentResolver是抽象类,它的实现是ContextImpl中的ApplicationContentResolver,是在ContextImpl的构造方法中创建的对象。
Uri bookUri = Uri.parse("content://com.sososeen09.knowledge.provider.book/book");
ContentValues values = new ContentValues();
values.put("_id", 6);
getContentResolver().insert(bookUri, values);
Cursor bookCursor = getContentResolver().query(bookUri, new String[]{"_id", "name"}, null, null, null);
Context的getContentResolver方法实际上获取的就是ContextImpl的ApplicationContentResolver类型的成员mContentResolver。
当ContentProvider所在进程还未创建时,第一次访问ContentProvider会触发ContentProvider所在进程的创建和ContentProvider对象的创建。通过ContentProvider的4个方法中的任何一个都会触发ContentProvider的启动过程。
源码分析
我们分析getContentResolver().query
方法触发的流程。
ContextWrapper的getContentResolver的方法如下,还是通过mBase来获取,这个mBase实际上是ContextImpl对象。
@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}
来看一下ContextImpl的getContentResolver方法,直接返回了一个成员变量mContentResolver。
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
这个mContentResolver实际上是ContentResolver的子类ApplicationContentResolver,该对象是在ContextImpl的构造方法中创建的。
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
...
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
获取了ContentResolver对象之后,调用它的query方法。在ContentResolver的query方法中首先会调用acquireUnstableProvider来获取一个IContentProvider对象。
在这里要说一下,返回值是IContentProvider对象,它继承自IInterface,也就是说它的实现类会是一个Binder对象。这也是因此ContentProvider不是一个Binder对象,而且一般ContentProvider和客户端不再同一个进程中。它的增删改查方法的结果肯定是需要一个通过一个Binder对象来进行IPC过程的传输。在这里就是IContentProvider。在这里它的实现是ContentProviderNative的子类ContentProvider.Transport。ContentProvider.Transport对象运行在ContentProvider的同一个进程,在远程有个特代理是ContentProviderProxy。
acquireUnstableProvider方法由ApplicationContentResolver实现,在ApplicationContentResolver中还有一个重写的方法是acquireProvider,它们都是做一个中转,调用的是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;
}
// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().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;
}
可以看到,它首先调用acquireExistingProvider,查看是否有缓存的IContentProvider对象,如果有的话就直接返回这个缓存对象。缓存存放在mProviderMap这个Map集合中。
// The lock of mProviderMap protects the following variables.
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
如果当前没有缓存的话,就需要通过一个IPC过程调用AMS的getContentProvider方法来获取一个ContentProviderHolder,ContentProviderHolder实现了Parcelable接口,因此它可以被进程间传递,它就是客户端的ContentProvider的一个代理对象的包装类。之后调用installProvider方法还要修改ContentProvider的引用计数器。
AMS的getContentProvider方法又会调用getContentProviderImpl方法,在该方法中会判断所要请求的ContentProvider进程是否已经存在,如果不存在的话就会调用startProcessLocked方法来创建ContentProvider的进程并安装ContentProvider。
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord r = null;
...
boolean checkCrossUser = true;
checkTime(startTime, "getContentProviderImpl: getProviderByName");
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
...
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
...
if (!providerRunning) {
...
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
...
proc.thread.scheduleInstallProvider(cpi);
}
} else {
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
...
}
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
...
}
...
return cpr != null ? cpr.newHolder(conn) : null;
}
从方法可以看出,如果ContentProvider没有在运行,而且它所在的进程没有存在的话就会调用AMS自身的startProcessLocked方法来创建进程。AMS的startProcessLocked会调用Process的start方法,在该方法表明所要启动一个新进程,并且调用android.app.ActivityThread的main方法作为入口。
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
...
}
App进程启动的流程如下,这里我们就不细讲了。
最终ActivityThread的main方法会被调用,该方法中会创建ActivityThread对象,并创建主线程的Looper对象,调用ActivityThread的attach方法,并且传递的参数为false,表明不是系统进程。之后就开始消息循环了。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// 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();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在ActivityThread的attach方法中,会通过一个IPC过程调用AMS的attachApplication方法。
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
} else {
...
}
...
}
AMS的attachApplication方法又会调用其attachApplicationLocked方法,在该方法中又会通过IPC过程调用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<String, IBinder> services, Bundle coreSettings) {
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;
sendMessage(H.BIND_APPLICATION, data);
}
AppBindData是一个JavaBean独享,用于ActivityThreadThread绑定的App的信息。
ApplicationThread的bindApplication方法是在Binder线程池中执行,因此通过一个Handler发送
H.BIND_APPLICATION消息切换到主线程。在Handler H的handleMessage方法中会从msg中取出AppBindData对象,并且调用ActivityThread的handleBindApplication方法。
在这里面做了5步操作:
- 创建ContextImpl对象
- 创建Instrumentation对象
- 创建Application对象
- 调用
installContentProviders(app, data.providers)
方法启动当前进程的ContentProvider并调用其onCreate方法 - 调用Application的onCreate方法
private void handleBindApplication(AppBindData data) {
...
// If the app is Honeycomb MR1 or earlier, switch its AsyncTask
// implementation to use the pool executor. Normally, we use the
// serialized executor as the default. This has to happen in the
// main thread so the main looper is set right.
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
...
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
...
// Instrumentation info affects the class loader, so load it before
// setting up the app context.
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
try {
ii = new ApplicationPackageManager(null, getPackageManager())
.getInstrumentationInfo(data.instrumentationName, 0);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find instrumentation info for: " + data.instrumentationName);
}
mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
mInstrumentationSplitAppDirs = ii.splitSourceDirs;
mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
mInstrumentedAppDir = data.info.getAppDir();
mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
mInstrumentedLibDir = data.info.getLibDir();
} else {
ii = null;
}
// 1 创建 ContextImpl对象
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
...
// 2 创建Instrumentation对象
// Continue loading instrumentation.
if (ii != null) {
final ApplicationInfo instrApp = new ApplicationInfo();
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
+ data.instrumentationName + ": " + e.toString(), e);
}
final ComponentName component = new ComponentName(ii.packageName, ii.name);
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
...
}
} else {
mInstrumentation = new Instrumentation();
}
...// 3 创建 Applcation对象
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
// 4 启动当前进程的ContentProvider,并调用其方法
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
// 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);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
... // 5 调用Application的onCreate方法
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
我们来看一下ActivityThread的installContentProviders方法。在该方法中主要遍历当前进程的ProviderInfo信息,通过调用installProvider方法来构建一个IActivityManager.ContentProviderHolder对象。
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
还记得我们之前说的吗,ContentProvider对象是无法跨进程调用的,因此需要一个Binder对象用于给客户端使用。ContentProviderHolder实现了Pacelable接口,可以在进程间传递数据。它实际上就是一个JavaBean对象,但是里面封装了IContentProvider,它实际上会作为一个Binder对象用于进程间方法的调用。我们前面也已经提了。IContentProvider的实现是ContentProviderNative的子类ContentProvider.Transport。ContentProvider.Transport对象运行在ContentProvider的同一个进程,在远程有个特代理是ContentProviderProxy。
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public IContentProvider provider;
public IBinder connection;
public boolean noReleaseNeeded;
...
}
我们来看一下ActivityThread的installProvider方法,可以看到首先通过类加载器创建了ContentProvider对象,然后调用了ContentProvider的attachInfo方法。
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
}
}
...
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
...
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
...
}
} else {
provider = holder.provider;
if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ info.name);
}
...
return retHolder;
}
我们再来看一下ContentProvider的attachInfo方法,该方法会调用3个参数的重载方法,在该方法中调用了ContextProvider的onCreate方法。
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
/*
* Only allow it to be set once, so after the content service gives
* this to us clients can't change it.
*/
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方法是在Application的onCreate方法之前调用的。当然了,还是要晚于Application的attachBaseContext方法。
ContentProvider创建完毕并启动之后还没有完事,会通过一个IPC过程调用AMS的publishContentProviders方法,此时传递ApplicationThread对象和创建完毕的ContentProviderHolder集合。publishContentProviders方法中也即是在AMS端存一下ContentProvider的记录,这里就不再细说了。
到此,ContentProvider所在的进程已经创建完毕,并且ContentProvider也已经全部启动起来。但是还没有完,调起ContentResolver发起query方法的那边还在等着返回结果呢。回到ContentResolver的query方法。注意此时客户端获取的IContentProvider对象是ContentProviderProxy,它是ContentProviderNative的内部类,通过IPC过程调用到ContentProviderNative.ContentProvider.Transport中。
# android.content.ContentResolver
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
...
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, 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,
selection, selectionArgs, sortOrder, 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, selection, sortOrder);
// 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;
...
}
再来看一下ContentProvider.Transport的query方法,由于ContentProvider.Transport是非静态内部类,因此持有ContentProvider的引用,所以内部调用了ContentProvider的query方法的返回值,返回的结果也会通过一个IPC过程返回到调用者那里。ContentProvider对外提供数据的方法,query、insert、delete、update方法也都是通过Transport进行调用的。
# android.content.ContentProvider.Transport
@Override
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
// The caller has no access to the data, so return an empty cursor with
// the columns in the requested order. The caller may ask for an invalid
// column and we would not catch that but this is not a problem in practice.
// We do not call ContentProvider#query with a modified where clause since
// the implementation is not guaranteed to be backed by a SQL database, hence
// it may not handle properly the tautology where clause we would have created.
if (projection != null) {
return new MatrixCursor(projection, 0);
}
// Null projection means all columns but we have no idea which they are.
// However, the caller may be expecting to access them my index. Hence,
// we have to execute the query as if allowed to get a cursor with the
// columns. We then use the column names to return an empty cursor.
Cursor cursor = ContentProvider.this.query(uri, projection, selection,
selectionArgs, sortOrder, 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, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
总结
访问一个ContentProvider需要用到ContentResolver对象,它是一个抽象类,实际上用的是它的实现类ContextImpl的ApplicationContentResolver。
访问ContextProvider时一个IPC过程,由于ContentProvider不能跨进程访问。调用ContentResolver的query等方法首先需要从AMS端获取一个ContextProvider的代理对象,这个代理对象实现了IContentProvider接口,它用于代理远端的Binder对象ContextProvider.Trasnport。ContextProvider.Trasnport继承自ContentProviderNative,ContentProviderNative实现了IContentProvider接口。通过ContextProvider.Trasnport的本地代理对象,可以调用ContextProvider.Trasnport的query方法,Trasnport是ContextProvider的内部类,持有ContextProvider的引用,它再去调用ContextProvider的方法并通过IPC过程返回结果。
第一次访问ContentProvider的时候,如果它还没有创建,AMS会通过startProcessLock方法调用Process的start方法,通过Zygote去fork一个进程之后调用ActivityThread的main方法,在main方法中创建ActivityThread对象,并调用其attach方法,在此过程创建了Instrumentation对象、Application对象,并创建该进程中对应的ContentProvider并调用其onCreate方法,此后调用Application的onCreate方法,因此ContentProvider的onCreate方法早于Application的onCreate方法执行,这也是四大组件中唯一一个比较特别的。