Android之本進(jìn)程ContentProvider啟動(dòng)流程分析
1、ContentProvider介紹
ContentProvider主要用于向外部提供數(shù)據(jù)
1、自己應(yīng)用進(jìn)程提供數(shù)據(jù)
2、其它app進(jìn)程的提供數(shù)據(jù)
這里分析本進(jìn)程的ContentProvider的啟動(dòng)過程
2、ContentProvider啟動(dòng)分析
1、我們知道Android程序入口在ActivityThread.java文件的main函數(shù)里面,如下代碼
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");
}
2、我們這里可以看到有關(guān)鍵函數(shù)thread.attach(false)方法,我們跟蹤進(jìn)去,attach部分方法如下
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public 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、這里有個(gè)關(guān)鍵方法,mgr.attachApplication(mAppThread),我們看下這個(gè)方法ActivityManagerService.java文件里面的實(shí)現(xiàn)
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
4、我們?cè)倏搓P(guān)鍵函數(shù)attachApplicationLocked函數(shù)部分實(shí)現(xiàn)
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、這里又調(diào)用了generateApplicationProvidersLocked(app)函數(shù),這個(gè)函數(shù)返回了一個(gè)ProviderInfo對(duì)象的集合,我們跟蹤這個(gè)函數(shù)看是如何得到這個(gè)集合的。
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進(jìn)程名字和app的uid,然后得到一個(gè)ProviderInfo的集合,就是這里的providers,然后我們遍歷這個(gè)集合,通過每個(gè)ProviderInfo的packageName和name屬性構(gòu)建ComponentName這個(gè)對(duì)象,然后再去構(gòu)建ContentProviderRecord對(duì)象,key為ComponentName,value為ContentProviderRecord添加到這個(gè)ProviderMap對(duì)象里面,也就是這行代碼
mProviderMap.putProviderByClass(comp, cpr);
然后把返回的providers作為參數(shù),傳遞給了bindApplication函數(shù)。
6、我們看下bindApplication函數(shù)的實(shí)現(xiàn),在ActivityThread.java文件里面看下實(shí)現(xiàn)
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);
}
我們可以看到發(fā)了一個(gè)攜帶providers數(shù)據(jù)的消息,消息是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;
很明顯,會(huì)調(diào)用handleBindApplication(data)方法。
7、我們看下handleBindApplication(data)方法部分實(shí)現(xiàn)
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
if (!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);
}
這里為什么我要說明下面這行函數(shù)呢?因?yàn)槲覀兛梢愿檓akeApplication函數(shù)里面去會(huì)調(diào)用我們平時(shí)代碼里面繼承了Application類的attachBaseContext函數(shù),這是我們一般app的Application類首先執(zhí)行的函數(shù)
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
我們來跟蹤下makeApplication函數(shù),傳遞的第二個(gè)參數(shù)是null,也就是Instrumentation傳遞進(jìn)去是null,這里的data.info對(duì)象是LoadedApk對(duì)象,所以我們需要到這個(gè)LoadedApk.java文件里面來看這個(gè)函數(shù)的部分實(shí)現(xiàn)如下
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);
}
}
}
因?yàn)镮nstrumentation傳遞進(jìn)去的是null,所以我們不會(huì)執(zhí)行 instrumentation.callApplicationOnCreate(app)方法,也就是不會(huì)執(zhí)行Application里面的onCreate方法,我們?cè)倏聪耺ActivityThread.mInstrumentation.newApplication這個(gè)方法,在Instrumentation.java文件看這個(gè)函數(shù)實(shí)現(xiàn)
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
接著看newApplication函數(shù)實(shí)現(xiàn)如下
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
然后再看這個(gè)Application的attach函數(shù)如下
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
我們發(fā)現(xiàn)這里已經(jīng)調(diào)用了我們平時(shí)見得很多在Application里面的attachBaseContext(context)方法
8、再來分析ContentProvider的調(diào)用,我們看下這個(gè)installContentProviders(app, providers)這個(gè)函數(shù),這里providers是攜帶過來的數(shù)據(jù),方法實(shí)現(xiàn)如下
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) {
}
}
我們可以看到這里調(diào)用了installProvider函數(shù),我們看下這個(gè)函數(shù)的調(diào)用,在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);
}
我們可以看到返回對(duì)象是IActivityManager.ContentProviderHolder,然后這里先獲取相應(yīng)的Context上下文信息,然后ClassLoader加載對(duì)應(yīng)的ContentProvider類,并創(chuàng)建該類的對(duì)象,然后我們調(diào)用了如下函數(shù),參數(shù)是上下文,和函數(shù)傳遞進(jìn)來的
ProviderInfo.
localProvider.attachInfo(c, info);
然后我們跟蹤這個(gè)函數(shù)到里面去,(在ContentProvider類文件里面)代碼如下,
public void attachInfo(Context context, ProviderInfo info) {
attachInfo(context, info, false);
}
繼續(xù)跟蹤這個(gè)函數(shù)attachInfo函數(shù)
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();
}
}
很明顯這里調(diào)用的ContentProvider的onCreate函數(shù),也就是我們平時(shí)見到的繼承ContentProvider類的onCreate函數(shù),這里ContentProvider就創(chuàng)建完了。
然后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變量,然后調(diào)用
IBinder jBinder = provider.asBinder();
IContentProvider可以理解為ContentProvider客戶端和服務(wù)端通信的接口,這里根據(jù)ProviderInfo的信息和Binder類型IContentProvider對(duì)象,創(chuàng)建一個(gè)ContentProviderHolder對(duì)象,它里邊封裝了這個(gè)ContentProvider的ProviderInfo和IContentProvider信息,然后又調(diào)用了下面的方法,我們跟蹤進(jìn)去
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;
}
然后這里根據(jù)Provider的信息構(gòu)造了ProviderClientRecord對(duì)象,authority是一個(gè)多屬性值,變量這個(gè)Provider對(duì)應(yīng)的所有authority,每個(gè)authority屬性為key,保存這個(gè)ProviderClientReocrd到mProviderMap的HashMap中
我們可以看下這個(gè)地方本地聲明的緩存存儲(chǔ)信息,在ActivityThread.java這個(gè)類文件中
// 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,來存儲(chǔ),然后構(gòu)建不同的map對(duì)象,分別是以authority為key、IBinder文key、ComponentName為key.
代碼后面還按照其它方式保存到內(nèi)存
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
按照不同的存儲(chǔ)類型分別保存不同的ContentProvider集合中。
然后我們?cè)诘?步開始的installContentProviders方法里面還有這個(gè)函數(shù)沒有分析,publishContentProviders函數(shù),代碼實(shí)現(xiàn)如下
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);
}
}
為每一個(gè)ContentProvider信息創(chuàng)建了一個(gè)ContentProviderRecord對(duì)象,保存到了ProviderMap集合中,啟動(dòng)的ContentProvider按照authority為key保存到ProviderMap中,這里工作主要就是將ContentProvider的信息保存到AMS服務(wù)中去。
AMS服務(wù)保存ContentProvider的信息主要是在類ProviderMap中,它里邊有兩種保存的Provider信息的集合
1. ProviderByClass
以ComponentName為key保存了ContentProviderRecord的信息
2. ProviderByName
以authority為key保存了ContentProviderRecord的信息
最后我們不是看到這個(gè)函數(shù),
notifyAll()
不同進(jìn)程間調(diào)用ContentProvider的時(shí)候,先會(huì)判斷該ContentProvider所在的進(jìn)程是否已經(jīng)啟動(dòng),如果有啟動(dòng)需要首先啟動(dòng)該進(jìn)程,在該進(jìn)程啟動(dòng)完成后這個(gè)ContentProvider也就啟動(dòng)起來了,比如在我們項(xiàng)目中,我們有2個(gè)進(jìn)程,然后一個(gè)ContentProvider在一個(gè)進(jìn)程里面,我們?cè)谧约篴pp通過下面的方法拉起ContentProvider
getContentResolver().insert
如果沒有啟動(dòng)的時(shí)候,AMS就會(huì)首先啟動(dòng)個(gè)進(jìn)程及ContentProvider,并把這個(gè)ContentProviderRecord添加到等待隊(duì)列mLaunchingProviders中去,如下聲明
final ArrayList<ContentProviderRecord> mLaunchingProviders
= new ArrayList<ContentProviderRecord>();
然后等他它啟動(dòng)完成,此處代碼就是新的進(jìn)程及ContentProvider啟動(dòng)完成后,首先判斷是否在等待進(jìn)程中,如果有,就將該ContentProvider信息從等待隊(duì)列中移除,并調(diào)用notifyAll來喚醒等待的工作。
9、最后分析handleBindApplication函數(shù)的最后一步
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 class
if (!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);
}
當(dāng)有觸發(fā)ContentProvider啟動(dòng)完成的時(shí)候,我們可以看到才去執(zhí)行
mInstrumentation.callApplicationOnCreate(app);
這里跟蹤進(jìn)去也就是Application的onCreate方法,所以它是在ContentProvider的onCreate后面(前提是同時(shí)啟動(dòng)Appliation和ContentProvider)
3、總結(jié)
AMS服務(wù)保存ContentProvider的信息主要是在類ProviderMap中,它里邊有兩種保存的Provider信息的集合
1. ProviderByClass
以ComponentName為key保存了ContentProviderRecord的信息
2. ProviderByName
以authority為key保存了ContentProviderRecord的信息
3、如果Applicaton和ContentProvider都會(huì)起來,確保ContentProvider在本進(jìn)程里面,不能單獨(dú)開辟一個(gè)進(jìn)程放ContentProvider,那么部分函數(shù)執(zhí)行順序如下
Application繼承類的的attachBaseContext方法----->ContentProvider繼承類的onCreate方法---->pplication繼承類的onCreate函數(shù)
4、如果是Applicaton和ContentProvider不在同進(jìn)程,不管是否在一個(gè)app里面的不同進(jìn)程還是在另外一個(gè)app的進(jìn)程,那么會(huì)先啟動(dòng)Application繼承類的的attachBaseContext方法----->Application繼承類的onCreate函數(shù),如果有另外一個(gè)進(jìn)程或者一個(gè)app觸發(fā)ContentProvider,那么依然部分函數(shù)執(zhí)行順序如下
Application繼承類的的attachBaseContext方法----->ContentProvider繼承類的onCreate方法---->pplication繼承類的onCreate函數(shù),因?yàn)槊總€(gè)進(jìn)程都有一個(gè)Application,所以會(huì)在ContentProvider里面再次啟動(dòng)一次Application
作者:chen.yu
深信服三年半工作經(jīng)驗(yàn),目前就職游戲廠商,希望能和大家交流和學(xué)習(xí),
微信公眾號(hào):編程入門到禿頭 或掃描下面二維碼
零基礎(chǔ)入門進(jìn)階人工智能(鏈接)