您的位置:首页 > 编程语言 > PHP开发

ContentProvider的工作过程

2016-04-27 10:47 597 查看

ContentProvider的工作过程

ContentProvider是一种内容共享型组件,它通过Binder向其他组件乃至其他应用提供数据,当ContentProvider所在的进程启动时,ContentProvider会同时启动并发布到AMS中。需要注意,ContentProvider的onCreate要先于Application的onCreate而执行。

当一个应用启动时,入口方法为ActivityThread的main方法,在main中创建ActivityThread的实例并创建主线程的消息队列,然后在ActivityThread的attach方法中远程调用AMS的attachApplication方法并将ApplicationThread对象提供给AMS。ApplicationThread是一个Binder对象,它的Binder接口是IApplicationThread,它主要用于ActivityThread和AMS间的通讯。在AMS的attachApplication方法中,会调用ApplicationThread的bindApplication方法(跨进程完成),bindApplication的逻辑会经过ActivityThread中的Handler切换到ActivityThread中执行,具体方法是handleBindApplication。

在handleBindApplication方法中,ActivityThread会创建Application对象并加载ContentProvider。需要注意,ContentProvider的onCreate要先于Application的onCreate而执行。



ContentProvider提供增删改查四个接口来操作数据源。这四个方法都是通过Binder来调用的,外界无法直接访问ContentProvider,只能通过AMS根据Uri来获取对应的ContentProvider的Binder接口IContentProvider,然后再通过IContentProvider来访问ContentProvider的数据源。

下面来分析单实例的ContentProvider的启动过程的源码。

访问ContentProvider需要通过ContentResolver(抽象类,具体实现是ApplicationContentResolver)。通过ContentProvider四个中任一方法都可以触发ContentProvider启动,这里选择query方法。

ContentProvider的query方法中,首先会获取IContentProvider对象(通过ApplicationContentResolve的acquireProvider方法实现)。

ApplicationContentResolve的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) {
}
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;
}


从ActivityThread中查找是否已经存在ContentProvider,存在直接返回。如果没有启动,那就发送一个进程间请求给AMS让其启动目标ContentProvider,再通过installProvider方法来修改引用计数。在AMS中首先会启动ContentProvider所在的进程,然后再启动ContentProvider。启动进程是由AMS的startProcessLocked方法完成,其内部主要通过Process的start方法来完成新进程启动,新进程启动后的入口方法为ActivityThread的main。

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());

AndroidKeyStoreProvider.install();

// 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方法来进行一系列初始化,接着开始循环消息队列。

ActivityThread的attach方法会将ApplicationThread对象通过AMS的attachApplication方法跨进程传递给AMS。AMS的attachApplication调用了attachApplicationLocked,attachApplicationLocked又调用了bindApplication,这个过程也是跨进程调用。

thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());


ActivityThread#ApplicationThread#bindApplication

public final void bindApplication(String processName, ApplicationInfo appInfo,
.....
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.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
sendMessage(H.BIND_APPLICATION, data);
}


发送BIND_APPLICATION消息,调用ActivityThread的handleBindApplication方法。此方法完成了ContentProvider的创建,分为四个步骤:

创建ContextImpl和Instrumentation

ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

try {
java.lang.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);
}

mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);


创建Application对象

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;


启动当前进程的ContentProvider并调用其onCreate方法

List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, 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);
}


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) {
}
}


final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);


通过类加载器完成ContentProvider对象的创建。

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的attachInfo来调用它的onCreate

调用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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: