ContentProvider 源码分析---之二
来源:互联网 发布:gtx1070 gpu数据 编辑:程序博客网 时间:2024/06/01 07:53
2.1 AMS获取ContentProvider
AMS中的ContentProvider方法调用流程图如下,
AMS的getContentProviderImpl主要逻辑如下,
1,安全检查
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))!= null) { throw new SecurityException(msg);}
2,调用PMS的resolveContentProvider方法匹配出目标ContentProvider注册的ContentProvider,这个匹配过程
和其他三大组件完全类似。
try { checkTime(startTime, "getContentProviderImpl: before resolveContentProvider"); cpi = AppGlobals.getPackageManager().resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");} catch (RemoteException ex) {}
3,如果目标ContentProvider的进程已经创建了,就调用目标ContentProvider的ActivityThread的scheduleInstallProvider
方法安装ContentProvider,
try { proc.thread.scheduleInstallProvider(cpi);} catch (RemoteException e) {}
4,如果目标ContentProvider的进程还未创建,就调用startProcessLocked方法创建进程,
proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false);
创建进程在此就不论述了,在创建进程的过程中会安装ContentProvider。
5,等待目标ContentProvider的安装,
synchronized (cpr) { while (cpr.provider == null) { if (cpr.launchingApp == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": launching app became null"); EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS, UserHandle.getUserId(cpi.applicationInfo.uid), cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name); return null; } try { if (DEBUG_MU) Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp=" + cpr.launchingApp); if (conn != null) { conn.waiting = true; } cpr.wait(); } catch (InterruptedException ex) { } finally { if (conn != null) { conn.waiting = false; } } } }
6,调用ContentProviderRecord的newHolder方法构造目标ContentProvider对象的代理。
return cpr != null ? cpr.newHolder(conn) : null;
2.2 小节论述步骤4和步骤5;
2.3小节论述步骤6.
2.2 目标进程安装ContentProvider
现在已经进入目标进程中了,ActivityThread的scheduleInstallProvider调用流程图如下,
ActivityThread的scheduleInstallProvider方法如下,
public void scheduleInstallProvider(ProviderInfo provider) { sendMessage(H.INSTALL_PROVIDER, provider);}
跨进程调用首先发送Handler消息,切换到主线程中执行。
内部类H的handleMessage方法对INSTALL_PROVIDER消息处理如下,
case INSTALL_PROVIDER: handleInstallProvider((ProviderInfo) msg.obj); break;
handleInstallProvider方法如下,
public void handleInstallProvider(ProviderInfo info) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { installContentProviders(mInitialApplication, Lists.newArrayList(info)); } finally { StrictMode.setThreadPolicy(oldPolicy); } }
在installContentProviders方法中,
A,首先调用installProvider方法安装Provider,
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
B,然后跨进程调用AMS的publishContentProviders方法通知Provider安装完成,
try { ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results);} catch (RemoteException ex) {}
2.2.1 ContentProvider的安装
以联系人数据库为例, packages/providers/ContactsProvider
installProvider方法主要逻辑如下,
1,利用反射构造ContentProvider对象,
final java.lang.ClassLoader cl = c.getClassLoader();localProvider = (ContentProvider)cl. loadClass(info.name).newInstance();
在联系人数据库中构造的是ContactsProvider2对象。
2,获取ContentProvider对象的IContentProvider代理,这样才可以被其他进程调用,
provider = localProvider.getIContentProvider();
ContactsProvider2继承于AbstractContactsProvider,
public class ContactsProvider2 extends AbstractContactsProvider implements OnAccountsUpdateListener {
AbstractContactsProvider继承于ContentProvider,
public abstract class AbstractContactsProvider extends ContentProvider implements SQLiteTransactionListener {
当然,Android系统中的所有数据库都继承于ContentProvider, getIContentProvider方法如下,
public IContentProvider getIContentProvider() { return mTransport;}
mTransport是ContentProvider的内部类Transport对象,在ContentProvider创建的时候创建,
private Transport mTransport = new Transport();
Transport继承于ContentProviderNative,
class Transport extends ContentProviderNative {
ContentProviderNative定义如下,
abstract public class ContentProviderNative extends Binder implements IContentProvider {
因此,客户端拿到的实际上是目标ContentProvider的代理Transport对象。
客户端调用目标ContentProvider的入口是Transport。
这和绑定service有些类似,只是service的binder在具体的service中实现。
目标ContentProvider在ContentProvider中统一实现了。
3,调用ContentProvider的attachInfo方法,
localProvider.attachInfo(c, info);
ContentProvider的attachInfo方法如下,
•••ContentProvider.this.onCreate();
直接调用ContentProvider的onCreate方法。
4,为IactivityManager的内部类ContentProviderHolder的相关变量赋值,
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;•••
并且, IactivityManager的内部类ContentProviderHolder的provider变量指向的就是ContentProvider的代理Transport对象。
public IContentProvider provider;
2.2.2 AMS的publishContentProviders处理
AMS的publishContentProviders方法部分代码如下,
public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {•••synchronized (dst) { dst.provider = src.provider;//赋值 dst.proc = r; dst.notifyAll();}
参数providers中的ContentProviderHolder对象是目标ContentProvider的Transport对象。
IactivityManager的内部类ContentProviderHolder实现了Parcelable接口,
public static class ContentProviderHolder implements Parcelable {
因此,可以进行系列化和反系列化, writeToParcel方法如下,
public void writeToParcel(Parcel dest, int flags) { info.writeToParcel(dest, 0); if (provider != null) { dest.writeStrongBinder(provider.asBinder()); } else { dest.writeStrongBinder(null); } dest.writeStrongBinder(connection); dest.writeInt(noReleaseNeeded ? 1 : 0);}
在publishContentProviders方法中,会释放线程锁,这样在getContentProviderImpl方法一直等待目标ContentProvider进程
安装完成的循环终于可以跳出来了, cpr.provider终于不等于0,
synchronized (cpr) { while (cpr.provider == null) { if (cpr.launchingApp == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": launching app became null"); EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS, UserHandle.getUserId(cpi.applicationInfo.uid), cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name); return null; } try { if (DEBUG_MU) Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp=" + cpr.launchingApp); if (conn != null) { conn.waiting = true; } cpr.wait(); } catch (InterruptedException ex) { } finally { if (conn != null) { conn.waiting = false; } } } }
这样,目标ContentProvider进程的ContentProvider终于安装好了。
2.3 构造目标ContentProvider对象的代理
AMS的getContentProviderImpl方法中最后返回的代码如下,
return cpr != null ? cpr.newHolder(conn) : null;
ContentProviderRecord的newHolder方法如下,
public ContentProviderHolder newHolder(ContentProviderConnection conn) { ContentProviderHolder holder = new ContentProviderHolder(info); holder.provider = provider; holder.noReleaseNeeded = noReleaseNeeded; holder.connection = conn; return holder;}
首先构造ContentProviderHolder对象,然后为该对象的变量赋值。
最后返回到客户端的ActivityThread的acquireProvider方法,
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;}// Install provider will increment the reference count for us, and break// any ties in the race.holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable);return holder.provider;
再次强调一遍,客户端持有的IcontentProvider对象就是目标ContentProvider的Transport对象。
也就是ContentResolver中的增删改查等方法中通过acquireProvider方法获取的IcontentProvider对象就是目标
ContentProvider的Transport对象。
- ContentProvider 源码分析---之二
- ContentProvider 源码分析---之三
- ContentProvider源码分析
- ContentProvider源码分析
- ContentProvider源码分析
- ContentProvider源码分析
- Android ContentProvider源码分析
- ContentProvider源码分析
- ContentProvider源码分析
- Android之ContentProvider的启动过程源码分析
- ContentProvider源码分析(原)
- ContentProvider源码分析(原)
- ContentProvider源码分析(原)
- Memcached源码分析之二
- AsyncTask源码分析之二
- LoaderManager源码分析之二
- AndFix 源码分析之二
- LDD3源码分析之llseek分析(二)
- 51nod 1714-B君的游戏(尼姆博弈)
- 【CUGBACM15级BC第22场 C】hdu 5144 NPY and shot
- 【第2章】Python基本元素:数字、字符串和变量
- HDU6129 Just do it(前缀异或+杨辉三角)
- 机器学习基石(2)
- ContentProvider 源码分析---之二
- Manacher总结
- 【BZOJ】1597 [Usaco2008 Mar]土地购买 DP
- 1060. 爱丁顿数(25)
- 启动活动
- 客户端与服务端的互动
- centos 7.2 一键安装lnmp 成功后通过IP访问不了服务器(已解决)
- 2017.08.18【NOIP2017提高组A组】模拟赛
- UML基础