ContentProvider启动过程and多进程调用全过程源码详解
Posted 刘镓旗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ContentProvider启动过程and多进程调用全过程源码详解相关的知识,希望对你有一定的参考价值。
之前有两篇文章分别说了应用的启动过程(Activity)插件化知识详细分解及原理 之应用的启动过程和Service的启动过程Service启动过程and新进程创建全过程源码分析这里涉及了多进程调用的关系,建议先看这两篇。今天来说一下ContentProvider的启动过程及都进程调用过程,至于ContentProvider如何使用就不说了。下面进入正题
首先我们知道如果我们要操作ContentProvider的话是通过getContentResolver来操作的,通常我们使用一般是这样的
//指定uri
Uri uri = Uri.parse("content://xxxxx");
//准备数据
ContentValues values = new ContentValues();
values.put("xx","xx");
//对该uri匹配的Provider进行处理
//插入
getContentResolver().insert(uri,values);
//查询
getContentResolver().query(uri,new String[]"xx",null,null,null);
//删除
getContentResolver().delete(uri,"id=?",new String[]"1");
//修改
getContentResolver().update(uri,values,"id=?",new String[]"1");
1、那么我们就从这里开始,那么我们先要去看一下getContentResolver()的代码了
public class ContextWrapper extends Context
Context mBase;
public ContextWrapper(Context base)
mBase = base;
@Override
public ContentResolver getContentResolver()
//调用了Context的getContentResolver方法
return mBase.getContentResolver();
2、我们发现点进去后进入到了ContextWrapper 中,然后又调用了Context的getContentResolver()方法,而我们之前的文章都分析过了Context的实现类是ContextImpl,那么我们直接去看ContextImpl中的getContentResolver方法,而Context是在哪里初始化被创建的都在Service启动过程and新进程创建全过程源码分析文章中有分析。
源码路径:
/frameworks/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context
....
//mContentResolver成员变量
private final ApplicationContentResolver mContentResolver;
....
//构造方法
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration)
....
构造方法中创建了ApplicationContentResolver,注意第二个参数,这是ActivityThread类型,这里是调用者的ActivityThread哦!!
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
....
@Override
public ContentResolver getContentResolver()
//返回了ApplicationContentResolver
return mContentResolver;
3、在ContextImpl的getContentResolver方法中返回了一个ApplicationContentResolver类型的对象,这个对象在ContextImpl的构造方法中初始化,这个类是ContextImpl的内部类,它继承于ContentProvider
private static final class ApplicationContentResolver extends ContentResolver
.....
4、到这里我们知道了getContentResolver()方法返回的是ContextImpl中的内部类ApplicationContentResolver 对象,这个对象在ContextImpl的构造方法中被初始化,创建的时候需要依赖调用者进程的ActivityThread,这里我们只跟踪一个query方法,因为系统给我们本来就提供了很多的Provider使用,但是我们并不知道它是怎么被运行的,所有我们通过这个方法来进行分析。因为返回的是ApplicationContentResolver 的对象,本来我们查看它的query方法就可以了,但是ApplicationContentResolver 并没有重写ContentResolver中的query、insert、delete、update方法,那么我们还是要去看ContentResolver中的方法
源码路径:
/frameworks/base/core/java/android/content/ContentResolver.java
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder)
//直接又调用了6个参数的query方法
return query(uri, projection, selection, selectionArgs, sortOrder, null);
5、上面直接又调用了6个参数的query方法,我们来看一下
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal)
//1、获取IContentProvider接口对象
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null)
return null;
IContentProvider stableProvider = null;
Cursor qCursor = null;
try
....
try
//2、通过获取的IContentProvider查询数据,并返回Cursor对象,在这里会线程阻塞,至于为什么接着往下看
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
catch (DeadObjectException e)
//在第2步调用过程中,远程进程已经死亡,试图恢复连接
unstableProviderDied(unstableProvider);
//连接后重新获取provider
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);
// 将返回的Cursor对象包装成CursorWrapperInner
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
stableProvider = null;
qCursor = null;
return wrapper;
catch (RemoteException e)
return null;
finally
if (qCursor != null)
qCursor.close();
if (cancellationSignal != null)
cancellationSignal.setRemote(null);
if (unstableProvider != null)
releaseUnstableProvider(unstableProvider);
if (stableProvider != null)
releaseProvider(stableProvider);
6、从查询到返回结果一共有3步,我们总结一下,然后一会再一一的分析
1。首先通过acquireUnstableProvider方法获取了IContentProvider对象,这里会线程阻塞,等待返回IContentProvider,为什么请接着看
2。通过调用返回的IContentProvider对象调用该对象的query方法,这里有两种情况,一种是正常调用成功并返回Cursor对象,另一种是调用过程中远程对象死亡然后捕获异常后再次重新尝试连接后再调用query方法。
3。将返回的Cursor对象进行包装,包装成CursorWrapperInner类型后返回给调用者。
上面三步走完就获取到了provider中的数据,这里最重要要看一下acquireUnstableProvider是如果取到了IContentProvider接口对象
6.1.1、首先通过acquireUnstableProvider方法获取了IContentProvider对象,注意,现在还是在ContentResolver中,看代码
//常量
public static final String SCHEME_CONTENT = "content";
//获取IContentProvider
public final IContentProvider acquireUnstableProvider(Uri uri)
//这里判断uri的scheme是否是content,就是我们写的uri是否是以
//content://开头的
if (!SCHEME_CONTENT.equals(uri.getScheme()))
return null;
//判断authorities是否为空
String auth = uri.getAuthority();
if (auth != null)
//如果不为空直接return了acquireUnstableProvider方法
return acquireUnstableProvider(mContext, uri.getAuthority());
return null;
7、上面首先判断了调用者传入的uri是否符合标准,然后直接return了两个参数的acquireUnstableProvider方法,我们在去看一下这个方法,还是在ContentResolver类中
/** @hide */
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
8、acquireUnstableProvider这竟然是一个抽象的方法,我们应该还记得上面最开始的getContentResolver()方法返回的是ContextImpl的内部类ApplicationContentResolver类型,ApplicationContentResolver继承于ContentResolver,那么也就是说他必须要实现这个父类的抽象方法,现在转到ContextImpl类中了
源码路径:
/frameworks/base/core/java/android/app/ContextImpl.java
private static final class ApplicationContentResolver extends ContentResolver
private final ActivityThread mMainThread;
....
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth)
//直接返回了ActivityThread类中的acquireProvider方法
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
9、在ContextImpl的内部类ApplicationContentResolver的acquireUnstableProvider方法直接返回了ActivityThread类中的acquireProvider方法,上面说过了ApplicationContentResolver在ContextImpl的构造中创建并传入了ActivityThread,这里的这个ActivityThread是调用者的 ,去查看这个方法
源码路径:
/frameworks/base/core/java/android/app/ActivityThread.java
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable)
//1.查看是否有缓存的IContentProvider,命中直接返回
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null)
return provider;
//通过AMS获取了被调用provider的信息
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;
// 加载provider并保存
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
//返回holder.provider
return holder.provider;
10、上面的方法先判断是否有这个provider的缓存,如果有直接返回,但是如果是第一次调用肯定是没有缓存,接着会通过AMS拿到这个被调用的provider的信息,然后加载被调用的provider并缓存起来,我们接着去看一下通过AMS拿到被调用provider的信息这个方法,ActivityManagerNative.getDefault().getContentProvider,
源码路径:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
再说一遍:ActivityManagerNative.getDefault()返回的是AMS的代理类,最终会通过BInder机制调用到AMS
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable)
//如果IApplicationThread 为空直接抛异常了
enforceNotIsolatedCaller("getContentProvider");
if (caller == null)
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
//返回getContentProviderImpl方法
return getContentProviderImpl(caller, name, null, stable, userId);
11、还是在AMS中,看getContentProviderImpl方法
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId)
//用来保存provider的信息
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this)
long startTime = SystemClock.elapsedRealtime();
//获取调用者的进程信息
ProcessRecord r = null;
if (caller != null)
r = getRecordForAppLocked(caller);
if (r == null)
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when getting content provider " + name);
boolean checkCrossUser = true;
checkTime(startTime, "getContentProviderImpl: getProviderByName");
// 查看provider信息是否被加载过,是否存在缓存
cpr = mProviderMap.getProviderByName(name, userId);
// If that didn't work, check if it exists for user and then
// verify that it's a singleton provider before using it.
if (cpr == null && userId != UserHandle.USER_OWNER)
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
if (cpr != null)
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid))
userId = UserHandle.USER_OWNER;
checkCrossUser = false;
else
cpr = null;
cpi = null;
//这里如果是第一次调用肯定是不会命中缓存
boolean providerRunning = cpr != null;
if (providerRunning)
//如果命中缓存
cpi = cpr.info;
String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
!= null)
throw new SecurityException(msg);
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
//判断provider的multiprocess是否为true,如果是true,provider则会在调用者的进程中初始化,
//multiprocess默认为false,默认系统只有一个该provider
if (r != null && cpr.canRunHere(r))
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
....
boolean singleton;
//没有命中缓存
if (!providerRunning)
try
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
//通过PackageManagerService得到provider所在应用程序的信息
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
catch (RemoteException ex)
if (cpi == null)
return null;
.....
//检查权限
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null)
throw new SecurityException(msg);
....
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
//判断provider这个类是否是第一次加载
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
final boolean firstClass = cpr == null;
if (firstClass)
final long ident = Binder.clearCallingIdentity();
try
checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
//获取provider的Application信息
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
if (ai == null)
Slog.w(TAG, "No package info for content provider "
+ cpi.name);
return null;
ai = getAppInfoForUser(ai, userId);
//创建provider的信息
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
catch (RemoteException ex)
// pm is in same process, this will never happen.
finally
Binder.restoreCallingIdentity(ident);
checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
//判断provider的multiprocess是否为true,如果是true,provider则会在调用者的进程中初始化,
//multiprocess默认为false,默认系统只有一个该provider
if (r != null && cpr.canRunHere(r))
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr.newHolder(null);
if (DEBUG_PROVIDER)
RuntimeException e = new RuntimeException("here");
Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
+ " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
//因为multiprocess所以会继续走到这里,系统中所有的provider都会存储在mLaunchingProviders
//的ArrayList中,以为默认系统只能有一个该provider的实例,这里是看一下是否有其他的应用已经
//实例了该provider,如果是肯定会存在mLaunchingProviders,那么i也就肯定小于N
final int N = mLaunchingProviders.size();
int i;
for (i=; i<N; i++)
if (mLaunchingProviders.get(i) == cpr)
break;
//如果走到这里说明没有其他应用实例该provider
if (i >= N)
final long origId = Binder.clearCallingIdentity();
try
....
//查看provider所属进程是否已经存在
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
//判断该进程是否已经启动了
if (proc != null && proc.thread != null)
if (DEBUG_PROVIDER)
Slog.d(TAG, "Installing in existing process " + proc);
checkTime(startTime, "getContentProviderImpl: scheduling install");
proc.pubProviders.put(cpi.name, cpr);
try
//使用ApplicationThread发送一条消息,加载provider,一会再分析
proc.thread.scheduleInstallProvider(cpi);
catch (RemoteException e)
else
//如果进程没有创建则创建一个新的进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, , "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
if (proc == null)
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
return null;
//将该provider的信息保存到mLaunchingProviders中
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
finally
Binder.restoreCallingIdentity(origId);
checkTime(startTime, "getContentProviderImpl: updating data structures");
//存入provider的信息
if (firstClass)
mProviderMap.putProviderByClass(comp, cpr);
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null)
conn.waiting = true;
.....
//返回provider的信息封装成ContentProviderHolder返回
return cpr != null ? cpr.newHolder(conn) : null;
12、上面方法非常的长,但是重点的代码都没有删除,这里也出现了几种情况,首先判断了被调用的provider是否之前已经存在,然后判断了multiprocess属性是否为true,如果为true将允许在调用者的进程中实例该provider,还判断了该provider所属进程是否已经被创建,如果创建直接使用ApplicationThread发送消息加载provider,如果没有创建则先创建一个进程,至于一个新进程的创建过程在Service启动过程and新进程创建全过程源码分析中有分析,这里不再贴进程启动的源码,直接说步骤然后到provider的加载的地方。
13、创建新进程调用了AMS中的方法startProcessLocked
14、真正创建进程的是通过Process的start的方法
15、创建被创建后会调用该进程的ActivityThread的main方法
16、然后接着调用ActivityThread.attach方法
17、在attach中会调用ActivityManagerService.attachApplication
18、在AMS的attachApplication方法中会获取需要在本进程中加载的provider,
19、AMS会调用ActivityThread.bindApplication方法
20、bindApplication方法中会发送一个消息到ActivityThread中的Handler里
21、ActivityThread中的Handler中调用了 handleBindApplication,我们从这里开始
private void handleBindApplication(AppBindData data)
....
//创建上下文对象
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
....
//准备初始化的数据
if (data.instrumentationName != null)
InstrumentationInfo ii = null;
try
ii = appContext.getPackageManager().
getInstrumentationInfo(data.instrumentationName, );
catch (PackageManager.NameNotFoundException e)
if (ii == null)
throw new RuntimeException(
"Unable to find instrumentation info for: "
+ data.instrumentationName);
mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
mInstrumentationSplitAppDirs = ii.splitSourceDirs;
mInstrumentationLibDir = ii.nativeLibraryDir;
mInstrumentedAppDir = data.info.getAppDir();
mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
mInstrumentedLibDir = data.info.getLibDir();
//准备创建Application的数据
ApplicationInfo instrApp = new ApplicationInfo();
instrApp.packageName = ii.packageName;
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
instrApp.splitSourceDirs = ii.splitSourceDirs;
instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
instrApp.dataDir = ii.dataDir;
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
//LoadedApk对象是APK文件在内存中的表示。 //Apk文件的相关信息,诸如Apk文件的代码和资源,甚至代码里面的Activity,Service等四大组件的信息我们都可以通过此对象获取
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
//创建新进程的Context
ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try
//创建Instrumentation对象
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);
//初始化Instrumentation
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);
....
else
mInstrumentation = new Instrumentation();
....
try
//通过创建Application并回调Application的attach方法
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode)
List<ProviderInfo> providers = data.providers;
if (providers != null)
//加载provider
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, *);
try
//回调Application的OnCreate方法
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);
22、看一下加载ContentProvider的方法installContentProviders
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
//通知AMS,ContentProvider已经加载完成 ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
catch (RemoteException ex)
23、先来看一下真正加载provider的方法installProvider
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
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
//加载provider
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
//调用了getIContentProvider
provider = localProvider.getIContentProvider();
if (provider == null)
return null;
//调用了provider的onCreate方法
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;
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap)
//调用了asBinder方法
IBinder jBinder = provider.asBinder();
//下面就是将provider的信息保存
if (localProvider != null)
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null)
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 (!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, , );
else
prc = stable
? new ProviderRefCount(holder, client, , )
: new ProviderRefCount(holder, client, , );
mProviderRefCountMap.put(jBinder, prc);
retHolder = prc.holder;
return retHolder;
24、上面的方法主要是加载ContentProvider,然后通过加载的ContentProvider调用了getIContentProvider方法赋值给了一个IContentProvider类型的变量,这里有玄机哦!我们看一下ContentProvider中的getIContentProvider方法
//成员变量 mTransport
private Transport mTransport = new Transport();
//getIContentProvider方法
public IContentProvider getIContentProvider()
return mTransport;
这里竟然返回的是Transport,我们看看这个Transport 是什么
class Transport extends ContentProviderNative
....
继承于ContentProviderNative ,再看看ContentProviderNative 是什么
abstract public class ContentProviderNative extends Binder implements IContentProvider
....
继承于Binder实现了IContentProvider,那么也就是说在ActivityThread中初始化Application的时候,加载的ContentProvider返回的是一个Binder对象,那么也就可以理解为什么ContentProvider可以远程调用了吧。
25、现在我们返回去再看22步中installContentProviders方法,到这里已经加载完了provider,然后installContentProviders方法中通过调yong ActivityManagerNative.getDefault().publishContentProviders,ContentProvider已经加载完成,然后到这里再回到第5步当中,当时说了会阻塞线程,能看到这的相信应该明白了,剩下的应该就不需要再分析了。
来总结一下 :
1、首先如果需要操作ContentProvider的需要通过getContentResolver来操作
2、getContentResolver返回的是ContextImpl的内部类ApplicationContentResolver对象,这个类在ContextImpl的构造方法中被创建,它继承于ContentResolver,但是并没有重写他的query、insert、delete、update等方法
3、ContentResolver中通过AMS和ActivityThread最终获得IContentResolver接口对象,这里会有很多的逻辑。
3.1 、首先判断了URl是否符合标准
3.2、通过ContextImpl的内部类ApplicationContentResolver发送消息到调用者的ActivityThread中查看是否有被调用的ContentProvider的缓存,如果有直接返回,如果没有调用AMS的getContentProvider方法
3.3、AMS的getContentProvider方法又调用了getContentProviderImpl方法,在这个方法中,判断了provider在AMS当中是否存在缓存,接着判断了multiprocess属性是否为true,如果为true代表该provider允许在调用者进程中创建实例,但是系统默认是fasle的,然后判断provider的进程是否已经被创建,如果没有被创建则调用AMS中的startProcessLocked方法通过Process.start方法创建这个provider所属的进程
3.4、进程被创建后执行该进程的ActivityThread中的main方法,在main方法中会开启消息循环,然后调用attach方法,在attach方法中通过调用了AMS中的attachApplicaiton方法,后又转到了AMS中的attachApplicationLocked中,在这里通过ActivityThread的bindApplication方法调回了ActivityThread中,在这里方法中初始化了一些信息后发送一条消息到ActivityThread中的Handler中,然后Handler中调用了handleBindApplicaiton方法,在这个方法中创建了Application方法,然后调用了installContentProviders方法
3.5、在installContentProviders方法中分了两步
第一步:开启了for循环来加载所有需要在这个进程创建的provider,for循环中调用了installProvide方法,在installProvider方法中加载ContentProvider类,通过加载的ContentProvider.getIContentProvider获取IContentProvider接口对象,这个接口对象是一个Binder对象,返回的是一个叫Transtorp类型的对象,这个对象继承于ContentProviderNative ,而ContentProviderNative继承于Binder并实现了IContentProvider接口,也就是说在这里被加载完的ContentProvider返回的是一个Binder类型的IContentProvider接口对象,所以它可以进场跨进程调用
第二部:加载ContentProvider类后调用AMS的publishContentProviders方法通知AMS,ContentProvider已经加载完成,并返回这个Binder类型的IContentProvider接口对象,然后就可以对该进程中的Provider进行操作了
OK,ContentProvider的操作流程也说完了,下一篇会说BroadcastReceiver,希望关注
以上是关于ContentProvider启动过程and多进程调用全过程源码详解的主要内容,如果未能解决你的问题,请参考以下文章
Android 源码分析 ContentProvider 启动
Android深入四大组件Content Provider的启动过程