一、ContentProvider 介绍
1.1、什么是ContentProvider
ContentProvider是跨进程对外提供信息的一种标准接口
信息提供者 可以自定义ContentProvider,在Manifest.xml向系统进行注册,并指定唯一标识authorities。
信息查询者 可以利用ContentResolver指定authorities 获取到IContentProvider,查询返回Cursor对象,获取查询结果。
1.2、ContentProvider的基本使用
1.2.1、内容提供者
定义ContentProvider
public class MyProvider extends ContentProvider{
private Context mContext;
DBHelper mDbHelper = null;
SQLiteDatabase db = null;
public static final String AUTOHORITY = "com.sogou.feifei";
// UriMatcher类使用:在ContentProvider 中注册URI
private static final UriMatcher mMatcher;
public static final int User_Code = 1;
public static final int Job_Code = 2;
static{
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 初始化
mMatcher.addURI(AUTOHORITY,"user", User_Code);
mMatcher.addURI(AUTOHORITY, "job", Job_Code);
// 若URI资源路径 = content://cn.scu.myprovider/user ,则返回注册码User_Code
// 若URI资源路径 = content://cn.scu.myprovider/job ,则返回注册码Job_Code
}
@Override
public boolean onCreate() {
mContext = getContext();
mDbHelper = new DBHelper(getContext());
db = mDbHelper.getWritableDatabase();
// 初始化两个表的数据(先清空两个表,再各加入一个记录)
db.execSQL("delete from user");
db.execSQL("insert into user values(1,'Carson');");
db.execSQL("insert into user values(2,'Kobe');");
db.execSQL("delete from job");
db.execSQL("insert into job values(1,'Android');");
db.execSQL("insert into job values(2,'iOS');");
Log.d("MyProvider","MyProvider was onCreate()");
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
// 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
// 该方法在最下面
String table = getTableName(uri);
// 查询数据
return db.query(table,projection,selection,selectionArgs,null,null,sortOrder,null);
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
// 由于不展示,此处不作展开
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
// 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
// 该方法在最下面
String table = getTableName(uri);
// 向该表添加数据
db.insert(table, null, values);
// 当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
mContext.getContentResolver().notifyChange(uri, null);
return uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
//...
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
//...
return 0;
}
/**
* 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
*/
private String getTableName(Uri uri){
String tableName = null;
switch (mMatcher.match(uri)) {
case User_Code:
tableName = DBHelper.USER_TABLE_NAME;
break;
case Job_Code:
tableName = DBHelper.JOB_TABLE_NAME;
break;
}
return tableName;
}
}
class DBHelper extends SQLiteOpenHelper {
// 数据库名
private static final String DATABASE_NAME = "finch.db";
private static final int DATABASE_VERSION = 1;
// 表名
public static final String USER_TABLE_NAME = "user";
public static final String JOB_TABLE_NAME = "job";
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 创建两个表格:用户表 和职业表
db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " name TEXT)");
db.execSQL("CREATE TABLE IF NOT EXISTS " + JOB_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " job TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Manifest.xml中声明 Provider,指定其authorities。authorities是ContentProvider在Android系统中的唯一标识。
1.2.2、内容使用者
- 构建查询的Uri
//(1)自定义Uri 指定查询“com.sogou.feifei”ContentProvider的User表
Uri uri_user = Uri.parse("content://com.sogou.feifei/user");
//(2) 获取ContentResolver
ContentResolver resolver = getContentResolver();
//(3)通过ContentResolver 根据URI 向ContentProvider中插入数据
resolver.insert(uri_user,values);
//(4)通过ContentResolver 向ContentProvider中查询数据
Cursor cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null);
while (cursor.moveToNext()){
System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1));
// 将表中数据全部输出
}
cursor.close();
二、几个重要的类
2.1、ContentProvider
ContentProvider是一个抽象类:
- 定义了insert、delete、updaete、query等抽象方法,具体的方法操作 由子类实现。
public abstract class ContentProvider implements ComponentCallbacks2 {
private Context mContext = null;
public abstract int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs);
public abstract int update(@NonNull Uri uri, @Nullable ContentValues values,
@Nullable String selection, @Nullable String[] selectionArgs);
public abstract @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values);
public abstract @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder);
private Transport mTransport = new Transport();
- ContentProvider内部持有一个Transport()对象,Transport是一个实现了IProvider接口的Binder类,用于对外提供IPC调用接口。
class Transport extends ContentProviderNative {
@Override
public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {}
@Override
public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {}
@Override
public int update(String callingPkg, Uri uri, ContentValues values, String selection,
String[] selectionArgs) {}
public abstract int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs);
}
abstract public class ContentProviderNative extends Binder implements IContentProvider {
}
2.2、ContentResolver
ContentResolver 用于数据使用方,向ContentProvider查询数据
- acquireProvider 方法 通过Uri中的authorities 在Android系统中查询对应的ContentProvider,返回ContentProvider的Bindder对象
- 通过IContentProvider 代理实现 insert、delete、query、update等操作。
public abstract class ContentResolver {
//向Android系统查询 uri对应的ContextProvider实例的Binder对象
public final IContentProvider acquireProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
final String auth = uri.getAuthority();
if (auth != null) {
return acquireProvider(mContext, auth);
}
return null;
}
public final @Nullable Cursor query(uri) {
return acquireProvider().query(uri)
}
public final @Nullable Uri insert(Uri url) {
return acquireProvider.insert(url)
}
public final int delete(Uri url){
return acquireProvider.delete(url)
}
public final int update(Uri uri) {
return acquireProvider(uri).update(uri)
}
}
2.3、ProviderInfo
ProviderInfo 代表一个Provider信息,对应manifest.xml中声明的一条Provider记录
public final class ProviderInfo extends ComponentInfo
implements Parcelable {
public String authority = null;
public String readPermission = null;
public String writePermission = null;
public boolean grantUriPermissions = false;
public PatternMatcher[] uriPermissionPatterns = null;
public PathPermission[] pathPermissions = null;
public boolean multiprocess = false;
}
2.4、ContentProviderHolder
ContentProviderHolder 数据持有者,持有ProviderInfo、IContentProvider对象,用于在IPC中传递参数
public class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public IContentProvider provider;
public IBinder connection;
public boolean noReleaseNeeded;
}
2.5、ProviderClientRecord
ProviderClientRecord 代表app端一条ContentProvider记录。
内部持有远端IContentProvider、本地ContentProvider实例和ContentProviderHolder实例
final class ProviderClientRecord {
final String[] mNames;
//mProvider 远端Provider实例
final IContentProvider mProvider;
//本地的Provider实例
final ContentProvider mLocalProvider;
final ContentProviderHolder mHolder;
ProviderClientRecord(String[] names, IContentProvider provider,
ContentProvider localProvider, ContentProviderHolder holder) {
mNames = names;
mProvider = provider;
mLocalProvider = localProvider;
mHolder = holder;
}
}
三、调用过程
- ContextResolver.query()
- ContextResolver.acquireUnstableProvider()
- ApplicationContentResolver.acquireUnstableProvider()
- ActivityThread.acquireProvider()
3.1、通过authority 在系统中查询 ContentProvider
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
//(1)首先查询自身有没有缓存过该ContentProvider,命中缓存则直接返回。
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
//(2)调用IActivityManager.getContentProvider()
ContentProviderHolder holder = null;
try {
synchronized (getGetProviderLock(auth, userId)) {
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), auth, userId, stable);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
//(3)将IActivityManager返回的ContentProviderHolder在本地进行安装
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
- 首先查询自身有没有缓存过该ContentProvider,命中缓存则直接返回
ActivityThread中的mProviderMap中保存这所有安装过的ContentProvider
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
incProviderRefLocked(prc, stable);
}
return provider;
}
}
- 若ActivityThread本地没有命中缓存的ContentProvider,则IPC调用IActivityMangaer.query() 向Android系统查询ContentProvider,查询结果保存在返回值ContentProviderHolder中
将IActivityManager返回的ContentProviderHolder在ActivityThread中进行安装
安装的过程会区分本地ContentProvider和远端ContentProvider
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
//(1) 当Holder.provider == null 时,说明查询的ContentProvider属于当前进程,在ActivityThread中本地实例化一个ContentProvider实例,安装后进行查询操作
//holder.provider != null,说明ContentProvider是运行在其他进程中,返回IProvider(Binder) IPC 跨进程查询。
if (holder == null || holder.provider == null) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
//在当前进程实例化一个ContentProvider
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info);
} else {
provider = holder.provider;
}
ContentProviderHolder retHolder;
//(2) 将LocalProvider和provider 封装成ProviderClientRecord 换成进入ActivityThread
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) { //对于本地ContentProvider
//本地创建一个ProviderClientRecord() 缓存在mLocalProviders和mLocalProvidersByName中。
holder = new 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 { //对于 远端ContentProvider
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;
}
当Holder.provider == null 时,说明查询的ContentProvider属于当前进程,在ActivityThread中本地实例化一个ContentProvider实例
holder.provider != null,说明ContentProvider运行在其他进程中,返回IProvider(Binder) IPC 跨进程查询
本地ContentProvider或者远端IContentProvider 封装成ProviderClientRecord 缓存在ActivityThread,方便下次复用。
3.2、ActivityManagerService 中查询ContentProvider
- ActivityManagerService.getContentProvider()
- ActivityManagerService.getContentProviderImpl()
ContentProvider的查询操作主要实现在getContentProviderImpl中,代码比较长,可以分几部分来看。
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
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);
}
}
//(1)查询ContentProvider 是否已经发布,发布后会缓存在mProviderMap中
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
cpi = cpr.info;
if (r != null && cpr.canRunHere(r)) {
//查询的ContentProvider允许 运行在调用者的进程,此时直接返回一个空的ContentProviderHolder给调用者进程,由调用者进程自己实例化ContentProvider实例。
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
conn = incProviderCountLocked(r, cpr, token, stable)
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
if (!providerRunning) { //查询ConntetProvider还没有发布,或者已发布但没有运行
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
//取出缓存的ContentProviderRecord,或者创建一个新的ContentProviderRecord,
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {
ApplicationInfo ai =AppGlobals.getPackageManager().getApplicationInfo(cpi.applicationInfo.packageName,STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
//创建一个ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
if (r != null && cpr.canRunHere(r)) {
//查询的ContentProvider 可以运行在调用者进程,则直接返回空的ContentProviderHolder,由调用者进程自己实例化ContentProvider
return cpr.newHolder(null);
}
//尝试启动ContentProvider,
//若ContetProvider所属的ProcessRecord进程存在,则直接调用proc.thread.scheduleInstallProvider(cpi);启动进程
//若ContentProvider所属的进程(ProcessRecord不存在)尚未启动,则首先启动ProcessrRecord进程
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// If the provider is not already being launched, then get it
// started.
if (i >= N) {
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
try {
//匹配上ContentProvider所属的进程,调用scheduleInstallProvider() 安装ContentProvider
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
//启动新的进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
}
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
//等待ContentProvider所属的进程启动,ContentProdier实例启动完成
// Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
3.2.1、查询ContentProvider 在ActivityManagerService中是否已经发布(已发布的ContentProvider会缓存在mProviderMap中)
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
3.2.2、若ContentProvider已经发布,并且ContentProvider所属的进程正在运行,如果ContentProvider可以在调用者进程中运行,则返回空的ContentProviderHolder,由调用者进程实例化一个本地的ContentProvider;否则在ActivityManagerService类中实例化一个ContentProviderConnection实例和ContentProviderRecord实例 备用。
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
cpi = cpr.info;
if (r != null && cpr.canRunHere(r)) {
//查询的ContentProvider允许 运行在调用者的进程,此时直接返回一个空的ContentProviderHolder给调用者进程,由调用者进程自己实例化ContentProvider实例。
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
conn = incProviderCountLocked(r, cpr, token, stable)
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
3.2.3、待查询的ConntetProvider在ActivityManagerService中还没有发布,则尝试安装该ContentProvider
ContentProvider可以在调用者进程中运行,则直接返回空的ContentProviderHolder
if (!providerRunning) { //查询ConntetProvider还没有发布,或者已发布但没有运行
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
//取出缓存的ContentProviderRecord,或者创建一个新的ContentProviderRecord,
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {
ApplicationInfo ai =AppGlobals.getPackageManager().getApplicationInfo(cpi.applicationInfo.packageName,STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
//创建一个ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}
if (r != null && cpr.canRunHere(r)) {
//查询的ContentProvider 可以运行在调用者进程,则直接返回空的ContentProviderHolder,由调用者进程自己实例化ContentProvider
return cpr.newHolder(null);
}
}
ContentProvider不是运行于调用者进程,则尝试安装该ContentProvider,分两种情况:
- 当ContentProvider所属的进程已经存在,则直接调用scheduleInstallProvider()安装ContentProvider
- 当前ContentProvider所属的进程不存在,则先启动进程
//尝试启动ContentProvider,
//若ContetProvider所属的ProcessRecord进程存在,则直接调用proc.thread.scheduleInstallProvider(cpi);启动进程
//若ContentProvider所属的进程(ProcessRecord不存在)尚未启动,则首先启动ProcessrRecord进程
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// If the provider is not already being launched, then get it
// started.
if (i >= N) {
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
try {
//匹配上ContentProvider所属的进程,调用scheduleInstallProvider() 安装ContentProvider
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
//启动新的进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
}
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
3.2.4、等待ContentProvider安装完成,然后返回ContentProviderHolder实例
若ContentProvider.provider==null,则调用cpr.wait(),lock主当前操作。
//等待ContentProvider所属的进程启动,ContentProdier实例启动完成
// Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
3.3、启动新进程,安装ContentProvider
承接上文 3.2.4 场景,新启动的ContentProvider需要,新启动进程,在新进程中安装ContentProvider
进程启动后,会调用ActivityThread.main()
- ActivityThread().attach()
- ActivityManagerService.attachApplication()
- ActivityManagerService.attachApplicationLocked()
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
//providers 即为Manifest.xml中提取出来的所有的ContentProvider,告知ApplicationThread 有哪些ContentProvider需要安装
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
return true;
}
- ApplicationThread.bindApplication()
- sendMessage(H.BIND_APPLICATION
- ActivityThread.handleBindApplication()
private void handleBindApplication(AppBindData data) {
//创建ContextImpl
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
//创建Instrumentation
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
final ComponentName component = new ComponentName(ii.packageName, ii.name);
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
//创建Application
Application app;
app = data.info.makeApplication(data.restrictedBackupMode, null);
//注意,这里是install ContentProvider
installContentProviders(app, data.providers);
//调用Application的onCreate方法
mInstrumentation.callApplicationOnCreate(app);
}
handleBindApplication方法干了很多事情
创建ContextImpl
创建Instrumentation
创建Application
创建ContentProvider,并调用其onCreate方法
调用Application的onCreate方法
我们继续深入installContentProviders方法,实例化ContentProvider之后会调用IActivityManager.publishContentProviders()
private void installContentProviders(
Context context, List providers) {
final ArrayList results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
//构建ContentProvider
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
//通过ClassLoader 反射构建ContentProvider
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
//attachInfo方法里面就会调用ContentProvider的onCreate方法
localProvider.attachInfo(c, info);
return retHolder;
}
我们再看publishContentProviders()方法。
public final void publishContentProviders(IApplicationThread caller,
List providers) {
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
final int N = providers.size();
for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (dst != null) {
int launchingCount = mLaunchingProviders.size();
int j;
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
}
}
}
}
publishContentProviders 内部 匹配对应的ContentProviderRecord,调用了ContentProviderRecord.notify()
此时因等待该ContentProvider启动而block主的代码就会恢复运行。见 3.2.4
四、小结
4.1、几点结论
- app启动的时候 会将Manifest.xml中声明的ContentProvider进行实例化并安装
- app本进程内安装之后,contentProvider实例 会在app本地进程进行缓存(mProviderMap),这样 app内自己调用contentResolver请求ContentProvider时,直接从缓存提取,不需向ActivityManagerService 进行IPC查询
- app进程内安装ContentProvider后,会调用IActivityManager.publishContentProviders()向ActivityManagerService进行注册发布 ,这些ContentProvider会缓存在ActivityManagerService(mProviderMap)中,标记为已发布,当其他进程ICP查询该ContentProvider时,可以直接将缓存结果直接通过IPC返回。
- app启动过程中,ContentProvider 先于Application 调用onCreate()方法
4.2、完整的调用时序图
下面是一张完整的ContentProvider的启动流程图
场景如下:
- App B 提供ContentProvider,但从未启动
- App A 通过authorities,首次向系统查询该ContentProvider
五、参考文章
ContentProvider基本使用
ContentProvider启动过程分析
https://blog.csdn.net/xfhy_/article/details/93138933
https://my.oschina.net/u/4580391/blog/4360153