基于Android U
ContentProvider,即内容提供者,主要用于进程内和进程间的数据共享。
当ContentProvider所在进程启动时,ContentProvider会同时启动并被发布到AMS中。需要注意的是,这时ContentProvider的onCreate()先于Application的onCreate()执行。
外界无法直接访问ContentProvider,只能通过AMS根据Uri获取对应ContentProvider的Binder接口IContentProvider,然后再通过IContentProvider来访问ContentProvider中的数据源。访问ContentProvider需要通过ContentResolver,ContentResolver是一个抽象类,通过Context的**getContentResolver()**方法获取。真正实现是ApplicationContentResolver(ContextImpl的内部类)。当ContentProvider所在的进程未启动时,第一次访问ContentResolver的方法时,就会启动该进程和ContentProvider。
通过增删改查四个方法的任何一个都可以触发ContentProvider的启动。
query方法到AMS的调用过程
1 2 3 4 frameworks/base/core/java/android/content/ContextWrapper.javapublic ContentResolver getContentResolver () { return mBase.getContentResolver(); }
mBase指的是ContextImpl。
1 2 3 4 frameworks/base/core/java/android/app/ContextImpl.javapublic ContentResolver getContentResolver () { return mContentResolver; }
getContentResolver()方法中返回了ApplicationContentResolver类型的mContentResolver对象,ApplicationContentResolver是ContextImpl中的静态内部类,继承自ContentResolver,它在ContextImpl的构造方法中被创建,这说明当我们调用ContentResolver的insert、query、update等方法时就会启动ContentProvider。这里以query()方法来举例,query()方法在ApplicationContentResolver的父类ContentResolver中实现,有3个重载方法,最终会调用如下的query()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 frameworks/base/core/java/android/content/ContentResolver.javapublic final @Nullable Cursor query (final @RequiresPermission .Read @NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { ... IContentProvider unstableProvider = acquireUnstableProvider(uri); ... try { ... try { qCursor = unstableProvider.query(mContext.getAttributionSource(), uri, projection, queryArgs, remoteCancellationSignal); } catch (DeadObjectException e) { ... } if (qCursor == null ) { return null ; } ... } catch (RemoteException e) { ... } finally { ... } }
注释1处通过acquireUnstableProvider()方法返回IContentProvider类型的unstableProvider对象,注释2处调用unstableProvider的query()方法。IContentProvider是ContentProvider在本地的代理,具体的实现为ContentProvider。
1 2 3 4 5 6 7 8 9 10 11 frameworks/base/core/java/android/content/ContentResolver.javapublic 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 ; }
注释1处检查uri的scheme是否等于SCHEME_CONTENT(值为”content”),如果不是则返回null。
注释2处调用了acquireUnstableProvider()方法,这是个抽象方法,它在ContentResolver的子类ApplicationContentResolver中实现,ApplicationContentResolver是ContextImpl的静态内部类。
1 2 3 4 5 6 7 8 frameworks/base/core/java/android/app/ContextImpl.javaprivate static final class ApplicationContentResolver extends ContentResolver { protected IContentProvider acquireUnstableProvider (Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false ); } }
在acquireUnstableProvider()方法中返回了ActivityThread类型的mMainThread对象的acquireProvider()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 frameworks/base/core/java/android/app/ActivityThread.javapublic 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 ; final ProviderKey key = getGetProviderKey(auth, userId); try { synchronized (key) { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable); ... } } catch (RemoteException ex) { ... } catch (InterruptedException e) { ... } finally { ... } ... holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable); return holder.provider; }
注释1处的acquireExistingProvider()方法内部会检查ActivityThread的全局变量mProviderMap中是否有目标ContentProvider存在,有则返回,没有就会在注释2处调用IActivityManager的getContentProvider()方法,最终会调用AMS的getContentProvider()方法。注释3处的installProvider()方法用来安装ContentProvider,并将注释2处返回的ContentProvider相关的数据存储在mProviderMap中,起到缓存的作用,这样使用相同的ContentProvider时,就不需要每次都调用AMS的getContentProvider()方法了。
1 2 3 4 5 6 7 8 9 10 11 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic final ContentProviderHolder getContentProvider ( IApplicationThread caller, String callingPackage, String name, int userId, boolean stable) { ... try { return mCpHelper.getContentProvider(caller, callingPackage, name, userId, stable); } finally { ... } }
调用的ContentProviderHelper的getContentProvider()。
1 2 3 4 5 6 7 frameworks/base/services/core/java/com/android/server/am/ContentProviderHelper.java ContentProviderHolder getContentProvider (IApplicationThread caller, String callingPackage, String name, int userId, boolean stable) { ... return getContentProviderImpl(caller, name, null , callingUid, callingPackage, null , stable, userId); }
getContentProvider()方法返回了getContentProviderImpl()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 frameworks/base/services/core/java/com/android/server/am/ContentProviderHelper.javaprivate ContentProviderHolder getContentProviderImpl (IApplicationThread caller, String name, IBinder token, int callingUid, String callingPackage, String callingTag, boolean stable, int userId) { ... synchronized (mService) { ... if (!providerRunning) { ... if (i >= numLaunchingProviders) { ... try { ... ProcessRecord proc = mService.getProcessRecordLocked( cpi.processName, cpr.appInfo.uid); IApplicationThread thread; if (proc != null && (thread = proc.getThread()) != null && !proc.isKilled()) { ... final ProcessProviderRecord pr = proc.mProviders; if (!pr.hasProvider(cpi.name)) { checkTime(startTime, "getContentProviderImpl: scheduling install" ); pr.installProvider(cpi.name, cpr); try { thread.scheduleInstallProvider(cpi); } catch (RemoteException e) { } } ... } else { ... proc = mService.startProcessLocked( cpi.processName, cpr.appInfo, false , 0 , new HostingRecord (HostingRecord.HOSTING_TYPE_CONTENT_PROVIDER, new ComponentName ( cpi.applicationInfo.packageName, cpi.name)), Process.ZYGOTE_POLICY_FLAG_EMPTY, false , false ); ... } ... } finally { ... } } ... } ... } ... }
注释1处通过getProcessRecordLocked()方法来获取目标ContentProvider的应用程序进程信息,这些信息用ProcessRecord类型的proc来表示,如果该应用程序进程已经启动就会调用注释2处的代码,否则就会调用注释3处的startProcessLocked()来启动进程。这里假设ContentProvider的应用程序进程还没有启动,应用程序进程启动最终会调用ActivityThread的main()方法。
1 2 3 4 5 6 7 8 9 10 11 12 frameworks/base/core/java/android/app/ActivityThread.javapublic static void main (String[] args) { ... Looper.prepareMainLooper(); ... ActivityThread thread = new ActivityThread (); thread.attach(false , startSeq); ... Looper.loop(); throw new RuntimeException ("Main thread loop unexpectedly exited" ); }
注释1处通过prepareMainLooper()方法在ThreadLocal中获取Looper,并在注释4处开启消息循环。注释2处创建了ActivityThread,紧接着调用了它的attach()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 frameworks/base/core/java/android/app/ActivityThread.javaprivate void attach (boolean system, long startSeq) { ... if (!system) { ... final IActivityManager mgr = ActivityManager.getService(); try { mgr.attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ... } else { ... } ... }
注释1处得到IActivityManager,注释2处调用IActivityManager的attachApplication()方法,并将ApplicationThread类型的mAppThread对象传进去,最终调用的是AMS的attachApplication()方法。
AMS启动ContentProvider的过程
1 2 3 4 5 6 7 8 9 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic final void attachApplication (IApplicationThread thread, long startSeq) { ... synchronized (this ) { ... attachApplicationLocked(thread, callingPid, callingUid, startSeq); ... } }
在attachApplicationLocked()方法中又调用了attachApplicationLocked()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaprivate void attachApplicationLocked (@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { ... try { ... final ActiveInstrumentation instr2 = app.getActiveInstrumentation(); ... if (app.getIsolatedEntryPoint() != null ) { thread.runIsolatedEntryPoint( app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs()); } else if (instr2 != null ) { thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage, providerList, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration (app.getWindowProcessController().getConfiguration()), app.getCompat(), getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, app.getDisabledCompatChanges(), serializedSystemFontMap, app.getStartElapsedTime(), app.getStartUptime()); } else { thread.bindApplication(processName, appInfo, app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage, providerList, null , profilerInfo, null , null , null , testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration (app.getWindowProcessController().getConfiguration()), app.getCompat(), getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, app.getDisabledCompatChanges(), serializedSystemFontMap, app.getStartElapsedTime(), app.getStartUptime()); } ... } catch (Exception e) { ... } }
在attachApplicationLocked()中调用了thread的bindApplication()方法,thread是IApplicationThread类型的,这里和IActivityManager一样采用了AIDL,ApplicationThread是ActivityThread的内部类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 frameworks/base/core/java/android/app/ActivityThread$ApplicationThreadprivate class ApplicationThread extends IApplicationThread .Stub { public final void bindApplication (String processName, ApplicationInfo appInfo, String sdkSandboxClientAppVolumeUuid, String sdkSandboxClientAppPackage, ProviderInfoList providerList, 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, AutofillOptions autofillOptions, ContentCaptureOptions contentCaptureOptions, long [] disabledCompatChanges, SharedMemory serializedSystemFontMap, long startRequestedElapsedTime, long startRequestedUptime) { if (services != null ) { ... ServiceManager.initServiceCache(services); } setCoreSettings(coreSettings); AppBindData data = new AppBindData (); data.processName = processName; data.appInfo = appInfo; data.sdkSandboxClientAppVolumeUuid = sdkSandboxClientAppVolumeUuid; data.sdkSandboxClientAppPackage = sdkSandboxClientAppPackage; data.providers = providerList.getList(); 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; data.autofillOptions = autofillOptions; data.contentCaptureOptions = contentCaptureOptions; data.disabledCompatChanges = disabledCompatChanges; data.mSerializedSystemFontMap = serializedSystemFontMap; data.startRequestedElapsedTime = startRequestedElapsedTime; data.startRequestedUptime = startRequestedUptime; updateCompatOverrideScale(compatInfo); CompatibilityInfo.applyOverrideScaleIfNeeded(config); sendMessage(H.BIND_APPLICATION, data); } }
在bindApplication()方法中最后调用sendMessage()方法向H发送BIND_APPLICATION类型消息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 frameworks/base/core/java/android/app/ActivityThread$Hclass H extends Handler { public void handleMessage (Message msg) { ... switch (msg.what) { case BIND_APPLICATION: ... handleBindApplication(data); ... break ; ... } ... } }
接下来执行handleBindApplication()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 frameworks/base/core/java/android/app/ActivityThread.javaprivate void handleBindApplication (AppBindData data) { ... Application app; ... try { app = data.info.makeApplicationInner(data.restrictedBackupMode, null ); ... mInitialApplication = app; ... if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); } } ... try { mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { ... } } finally { ... } ... }
注释1处创建Application,注释2处在非受限模式下启动ContentProvider,注释3处执行Application的onCreate()方法。
ContentProvider的启动时机是在Application创建后,Application#onCreate()调用前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 frameworks/base/core/java/android/app/ActivityThread.javaprivate void installContentProviders ( Context context, List<ProviderInfo> providers) { final ArrayList<ContentProviderHolder> results = new ArrayList <>(); for (ProviderInfo cpi : providers) { ... ContentProviderHolder cph = installProvider(context, null , cpi, false , true , true ); if (cph != null ) { cph.noReleaseNeeded = true ; results.add(cph); } } try { ActivityManager.getService().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } }
注释1处遍历当前应用程序进程的ProviderInfo列表,得到每个ContentProvider的ProviderInfo(存储ContentProvider的信息),并在注释2处调用installProvider()方法来启动这些ContentProvider。注释3处通过AMS的publishContentProviders()方法将这些ContentProvider存储在AMS的mProviderMap中,这个mProviderMap在前面提到过,起到缓存的作用,防止每次使用相同的ContentProvider时都会调用AMS的getContentProvider()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 frameworks/base/core/java/android/app/ActivityThread.javaprivate 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)) { 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) { } } ... try { final java.lang.ClassLoader cl = c.getClassLoader(); LoadedApk packageInfo = peekPackageInfo(ai.packageName, true ); if (packageInfo == null ) { packageInfo = getSystemContext().mPackageInfo; } localProvider = packageInfo.getAppFactory() .instantiateProvider(cl, info.name); provider = localProvider.getIContentProvider(); ... localProvider.attachInfo(c, info); } catch (java.lang.Exception e) { ... } } else { ... } ... }
注释1处首先获取Context,一般情况下就是Application;
注释2处获取应用信息;
注释3处通过AppComponentFactory实例化ContentProvider;
注释4处初始化ContentProvider,调用其onCreate()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 frameworks/base/core/java/android/content/ContentProvider.javapublic void attachInfo (Context context, ProviderInfo info) { attachInfo(context, info, false ); }private void attachInfo (Context context, ProviderInfo info, boolean testing) { ... if (mContext == null ) { mContext = context; ... ContentProvider.this .onCreate(); } }
注释1处在attachInfo()方法中调用了onCreate()方法,它是一个抽象方法,这样ContentProvider就启动完毕。