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对象就是目标ContentProviderTransport对象。

也就是ContentResolver中的增删改查等方法中通过acquireProvider方法获取的IcontentProvider对象就是目标

ContentProviderTransport对象。

原创粉丝点击