1、ContentProvider介绍
ContentProvider主要用于向外部提供数据
1、自己应用进程提供数据
2、其它app进程的提供数据
这里分析本进程的ContentProvider的启动过程
2、ContentProvider启动分析
1、我们知道Android程序入口在ActivityThread.java文件的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 libcoreEventLogger.setReporter(new EventLoggingReporter());AndroidKeyStoreProvider.install();// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal 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(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}
2、我们这里可以看到有关键函数thread.attach(false)方法,我们跟踪进去,attach部分方法如下
private void attach(boolean system) {sCurrentActivityThread = this;mSystemThread = system;if (!system) {ViewRootImpl.addFirstDrawHandler(new Runnable() {@Overridepublic void run() {ensureJitEnabled();}});android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",UserHandle.myUserId());RuntimeInit.setApplicationObject(mAppThread.asBinder());final IActivityManager mgr = ActivityManagerNative.getDefault();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {// Ignore}// Watch for getting close to heap limit.BinderInternal.addGcWatcher(new Runnable() {@Override public void run() {if (!mSomeActivitiesChanged) {return;}Runtime runtime = Runtime.getRuntime();long dalvikMax = runtime.maxMemory();long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();if (dalvikUsed > ((3*dalvikMax)/4)) {if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)+ " total=" + (runtime.totalMemory()/1024)+ " used=" + (dalvikUsed/1024));mSomeActivitiesChanged = false;try {mgr.releaseSomeActivities(mAppThread);} catch (RemoteException e) {}}}});
*******
3、这里有个关键方法,mgr.attachApplication(mAppThread),我们看下这个方法ActivityManagerService.java文件里面的实现
@Overridepublic final void attachApplication(IApplicationThread thread) {synchronized (this) {int callingPid = Binder.getCallingPid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid);Binder.restoreCallingIdentity(origId);}}
4、我们再看关键函数attachApplicationLocked函数部分实现
private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {*******boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;*******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());updateLruProcessLocked(app, false, null);app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
5、这里又调用了generateApplicationProvidersLocked(app)函数,这个函数返回了一个ProviderInfo对象的集合,我们跟踪这个函数看是如何得到这个集合的。
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {List<ProviderInfo> providers = null;try {ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager().queryContentProviders(app.processName, app.uid,STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);providers = slice != null ? slice.getList() : null;} catch (RemoteException ex) {}if (DEBUG_MU) Slog.v(TAG_MU,"generateApplicationProvidersLocked, app.info.uid = " + app.uid);int userId = app.userId;if (providers != null) {int N = providers.size();app.pubProviders.ensureCapacity(N + app.pubProviders.size());for (int i=0; i<N; i++) {ProviderInfo cpi =(ProviderInfo)providers.get(i);boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,cpi.name, cpi.flags);if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {providers.remove(i);N--;i--;continue;}ComponentName comp = new ComponentName(cpi.packageName, cpi.name);ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);if (cpr == null) {cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);mProviderMap.putProviderByClass(comp, cpr);}if (DEBUG_MU) Slog.v(TAG_MU,"generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);app.pubProviders.put(cpi.name, cpr);if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,mProcessStats);}ensurePackageDexOpt(cpi.applicationInfo.packageName);}}return providers;}
这里很明显是查询ContentProvider通过app进程名字和app的uid,然后得到一个ProviderInfo的集合,就是这里的providers,然后我们遍历这个集合,通过每个ProviderInfo的packageName和name属性构建ComponentName这个对象,然后再去构建ContentProviderRecord对象,key为ComponentName,value为ContentProviderRecord添加到这个ProviderMap对象里面,也就是这行代码
mProviderMap.putProviderByClass(comp, cpr);
然后把返回的providers作为参数,传递给了bindApplication函数。
6、我们看下bindApplication函数的实现,在ActivityThread.java文件里面看下实现
public final void bindApplication(String processName, ApplicationInfo appInfo,List<ProviderInfo> providers, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,IInstrumentationWatcher instrumentationWatcher,IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,Bundle 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.enableOpenGlTrace = enableOpenGlTrace;data.restrictedBackupMode = isRestrictedBackupMode;data.persistent = persistent;data.config = config;data.compatInfo = compatInfo;data.initProfilerInfo = profilerInfo;sendMessage(H.BIND_APPLICATION, data);}
我们可以看到发了一个携带providers数据的消息,消息是H.BIND_APPLICATION,handler类里面的handleMessage方法里面的收到消息处理如下
case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");AppBindData data = (AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;
很明显,会调用handleBindApplication(data)方法。
7、我们看下handleBindApplication(data)方法部分实现
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 classif (!data.restrictedBackupMode) {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);}}// 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);}catch (Exception e) {throw new RuntimeException("Exception thrown in onCreate() of "+ data.instrumentationName + ": " + e.toString(), e);}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 {StrictMode.setThreadPolicy(savedPolicy);}
这里为什么我要说明下面这行函数呢?因为我们可以跟踪makeApplication函数里面去会调用我们平时代码里面继承了Application类的attachBaseContext函数,这是我们一般app的Application类首先执行的函数
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
我们来跟踪下makeApplication函数,传递的第二个参数是null,也就是Instrumentation传递进去是null,这里的data.info对象是LoadedApk对象,所以我们需要到这个LoadedApk.java文件里面来看这个函数的部分实现如下
public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {if (mApplication != null) {return mApplication;}Application app = null;String appClass = mApplicationInfo.className;if (forceDefaultAppClass || (appClass == null)) {appClass = "android.app.Application";}try {java.lang.ClassLoader cl = getClassLoader();if (!mPackageName.equals("android")) {initializeJavaContextClassLoader();}ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);appContext.setOuterContext(app);} catch (Exception e) {if (!mActivityThread.mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to instantiate application " + appClass+ ": " + e.toString(), e);}}mActivityThread.mAllApplications.add(app);mApplication = app;if (instrumentation != null) {try {instrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!instrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}}
因为Instrumentation传递进去的是null,所以我们不会执行 instrumentation.callApplicationOnCreate(app)方法,也就是不会执行Application里面的onCreate方法,我们再看下mActivityThread.mInstrumentation.newApplication这个方法,在Instrumentation.java文件看这个函数实现
public Application newApplication(ClassLoader cl, String className, Context context)throws InstantiationException, IllegalAccessException, ClassNotFoundException {return newApplication(cl.loadClass(className), context);}
接着看newApplication函数实现如下
static public Application newApplication(Class<?> clazz, Context context)throws InstantiationException, IllegalAccessException, ClassNotFoundException {Application app = (Application)clazz.newInstance();app.attach(context);return app;}
然后再看这个Application的attach函数如下
/* package */ final void attach(Context context) {attachBaseContext(context);mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;}
我们发现这里已经调用了我们平时见得很多在Application里面的attachBaseContext(context)方法
8、再来分析ContentProvider的调用,我们看下这个installContentProviders(app, providers)这个函数,这里providers是携带过来的数据,方法实现如下
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) {}}
我们可以看到这里调用了installProvider函数,我们看下这个函数的调用,在ActivityThread.java文件里面
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) {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;}try {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);} 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 {provider = holder.provider;if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "+ info.name);}
我们可以看到返回对象是IActivityManager.ContentProviderHolder,然后这里先获取相应的Context上下文信息,然后ClassLoader加载对应的ContentProvider类,并创建该类的对象,然后我们调用了如下函数,参数是上下文,和函数传递进来的
ProviderInfo.
localProvider.attachInfo(c, info);
然后我们跟踪这个函数到里面去,(在ContentProvider类文件里面)代码如下,
public void attachInfo(Context context, ProviderInfo info) {attachInfo(context, info, false);}
继续跟踪这个函数attachInfo函数
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函数,也就是我们平时见到的继承ContentProvider类的onCreate函数,这里ContentProvider就创建完了。
然后installProvider方法还有部分如下
IActivityManager.ContentProviderHolder retHolder;synchronized (mProviderMap) {if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider+ " / " + info.name);IBinder jBinder = provider.asBinder();if (localProvider != null) {ComponentName cname = new ComponentName(info.packageName, info.name);ProviderClientRecord pr = mLocalProvidersByName.get(cname);if (pr != null) {if (DEBUG_PROVIDER) {Slog.v(TAG, "installProvider: lost the race, "+ "using existing local provider");}provider = pr.mProvider;} else {holder = new IActivityManager.ContentProviderHolder(info);holder.provider = provider;holder.noReleaseNeeded = true;pr = installProviderAuthoritiesLocked(provider, localProvider, holder);mLocalProviders.put(jBinder, pr);mLocalProvidersByName.put(cname, pr);}retHolder = pr.mHolder;} else {ProviderRefCount prc = mProviderRefCountMap.get(jBinder);if (prc != null) {if (DEBUG_PROVIDER) {Slog.v(TAG, "installProvider: lost the race, updating ref count");}// We need to transfer our new reference to the existing// ref count, releasing the old one... but only if// release is needed (that is, it is not running in the// system process).if (!noReleaseNeeded) {incProviderRefLocked(prc, stable);try {ActivityManagerNative.getDefault().removeContentProvider(holder.connection, stable);} catch (RemoteException e) {//do nothing content provider object is dead any way}}} else {ProviderClientRecord client = installProviderAuthoritiesLocked(provider, localProvider, holder);if (noReleaseNeeded) {prc = new ProviderRefCount(holder, client, 1000, 1000);} else {prc = stable? new ProviderRefCount(holder, client, 1, 0): new ProviderRefCount(holder, client, 0, 1);}mProviderRefCountMap.put(jBinder, prc);}retHolder = prc.holder;}}return retHolder;}
获取ContetProvider的IContentProvider赋值给provider变量,然后调用
IBinder jBinder = provider.asBinder();
IContentProvider可以理解为ContentProvider客户端和服务端通信的接口,这里根据ProviderInfo的信息和Binder类型IContentProvider对象,创建一个ContentProviderHolder对象,它里边封装了这个ContentProvider的ProviderInfo和IContentProvider信息,然后又调用了下面的方法,我们跟踪进去
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {final String auths[] = holder.info.authority.split(";");final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);final ProviderClientRecord pcr = new ProviderClientRecord(auths, provider, localProvider, holder);for (String auth : auths) {final ProviderKey key = new ProviderKey(auth, userId);final ProviderClientRecord existing = mProviderMap.get(key);if (existing != null) {Slog.w(TAG, "Content provider " + pcr.mHolder.info.name+ " already published as " + auth);} else {mProviderMap.put(key, pcr);}}return pcr;}
然后这里根据Provider的信息构造了ProviderClientRecord对象,authority是一个多属性值,变量这个Provider对应的所有authority,每个authority属性为key,保存这个ProviderClientReocrd到mProviderMap的HashMap中
我们可以看下这个地方本地声明的缓存存储信息,在ActivityThread.java这个类文件中
// The lock of mProviderMap protects the following variables.final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap= new ArrayMap<ProviderKey, ProviderClientRecord>();final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap= new ArrayMap<IBinder, ProviderRefCount>();final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders= new ArrayMap<IBinder, ProviderClientRecord>();final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName= new ArrayMap<ComponentName, ProviderClientRecord>();
通过不同的key,来存储,然后构建不同的map对象,分别是以authority为key、IBinder文key、ComponentName为key.
代码后面还按照其它方式保存到内存
mLocalProviders.put(jBinder, pr);mLocalProvidersByName.put(cname, pr);
按照不同的存储类型分别保存不同的ContentProvider集合中。
然后我们在第8步开始的installContentProviders方法里面还有这个函数没有分析,publishContentProviders函数,代码实现如下
public final void publishContentProviders(IApplicationThread caller,List<ContentProviderHolder> providers) {if (providers == null) {return;}enforceNotIsolatedCaller("publishContentProviders");synchronized (this) {final ProcessRecord r = getRecordForAppLocked(caller);if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);if (r == null) {throw new SecurityException("Unable to find app for caller " + caller+ " (pid=" + Binder.getCallingPid()+ ") when publishing content providers");}final long origId = Binder.clearCallingIdentity();final int N = providers.size();for (int i=0; i<N; i++) {ContentProviderHolder src = providers.get(i);if (src == null || src.info == null || src.provider == null) {continue;}ContentProviderRecord dst = r.pubProviders.get(src.info.name);if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);if (dst != null) {ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);mProviderMap.putProviderByClass(comp, dst);String names[] = dst.info.authority.split(";");for (int j = 0; j < names.length; j++) {mProviderMap.putProviderByName(names[j], dst);}int NL = mLaunchingProviders.size();int j;for (j=0; j<NL; j++) {if (mLaunchingProviders.get(j) == dst) {mLaunchingProviders.remove(j);j--;NL--;}}synchronized (dst) {dst.provider = src.provider;dst.proc = r;dst.notifyAll();}updateOomAdjLocked(r);maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,src.info.authority);}}Binder.restoreCallingIdentity(origId);}}
为每一个ContentProvider信息创建了一个ContentProviderRecord对象,保存到了ProviderMap集合中,启动的ContentProvider按照authority为key保存到ProviderMap中,这里工作主要就是将ContentProvider的信息保存到AMS服务中去。
AMS服务保存ContentProvider的信息主要是在类ProviderMap中,它里边有两种保存的Provider信息的集合
1. ProviderByClass
以ComponentName为key保存了ContentProviderRecord的信息
2. ProviderByName
以authority为key保存了ContentProviderRecord的信息
最后我们不是看到这个函数,
notifyAll()
不同进程间调用ContentProvider的时候,先会判断该ContentProvider所在的进程是否已经启动,如果有启动需要首先启动该进程,在该进程启动完成后这个ContentProvider也就启动起来了,比如在我们项目中,我们有2个进程,然后一个ContentProvider在一个进程里面,我们在自己app通过下面的方法拉起ContentProvider
getContentResolver().insert
如果没有启动的时候,AMS就会首先启动个进程及ContentProvider,并把这个ContentProviderRecord添加到等待队列mLaunchingProviders中去,如下声明
final ArrayList<ContentProviderRecord> mLaunchingProviders= new ArrayList<ContentProviderRecord>();
然后等他它启动完成,此处代码就是新的进程及ContentProvider启动完成后,首先判断是否在等待进程中,如果有,就将该ContentProvider信息从等待队列中移除,并调用notifyAll来唤醒等待的工作。
9、最后分析handleBindApplication函数的最后一步
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();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 classif (!data.restrictedBackupMode) {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);}}// 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);}catch (Exception e) {throw new RuntimeException("Exception thrown in onCreate() of "+ data.instrumentationName + ": " + e.toString(), e);}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 {StrictMode.setThreadPolicy(savedPolicy);}
当有触发ContentProvider启动完成的时候,我们可以看到才去执行
mInstrumentation.callApplicationOnCreate(app);
这里跟踪进去也就是Application的onCreate方法,所以它是在ContentProvider的onCreate后面(前提是同时启动Appliation和ContentProvider)
3、总结
AMS服务保存ContentProvider的信息主要是在类ProviderMap中,它里边有两种保存的Provider信息的集合
1. ProviderByClass
以ComponentName为key保存了ContentProviderRecord的信息
2. ProviderByName
以authority为key保存了ContentProviderRecord的信息
3、如果Applicaton和ContentProvider都会起来,确保ContentProvider在本进程里面,不能单独开辟一个进程放ContentProvider,那么部分函数执行顺序如下
Application继承类的的attachBaseContext方法----->ContentProvider继承类的onCreate方法---->pplication继承类的onCreate函数
4、如果是Applicaton和ContentProvider不在同进程,不管是否在一个app里面的不同进程还是在另外一个app的进程,那么会先启动Application继承类的的attachBaseContext方法----->Application继承类的onCreate函数,如果有另外一个进程或者一个app触发ContentProvider,那么依然部分函数执行顺序如下
Application继承类的的attachBaseContext方法----->ContentProvider继承类的onCreate方法---->pplication继承类的onCreate函数,因为每个进程都有一个Application,所以会在ContentProvider里面再次启动一次Application